Thirdweb is a platform that gives a set of instruments for creators, artists, and entrepreneurs to construct, launch and handle a Web3 mission simply.
It allows customers so as to add options reminiscent of 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 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 may 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, 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.
Usually phrases, DAOs are member-owned communities with out centralized management. The exact authorized standing of the sort of enterprise group is unclear. A DAO’s monetary transaction data and program guidelines are maintained on a blockchain.
Organising the DAO Consumer-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 beneath command:
yarn add @thirdweb-dev/cli
Thirdweb incorporates starters that assist generate a base setup on your mission. Use the command beneath to generate a Thirdweb starter mission. Kind a mission title and identify of your alternative for the mission listing. Observe 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 beneath to start out 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 dwell on the blockchain. And to do this, you should 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, on your web site to speak to the blockchain, you should in some way join your pockets to it. When you join your pockets to the web site, your web site could 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 stream is fairly self-explanatory.
When you arrange your pockets, swap 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 price messing up. You are going to begin with a “testnet,” which is a clone of “mainnet,” however it makes use of faux funds; you may check 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 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, on your web site to speak to the blockchain, you should in some way join your pockets to it. When you join your pockets to your web site, the web site could have permission to name sensible contracts in your behalf. Bear in mind, it is identical to authenticating into an internet site.
You might have constructed “Hook up with Pockets” buttons previously! This time, you may be utilizing thirdweb’s front-end SDK
, which makes it loopy simple.
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 thing with
<ThirdwebProvider>
. This supplier holds the consumer’s authenticated pockets information
Be aware: In case you’ve labored on dapps earlier than, be sure you disconnect your pockets from localhost:3000 on Metamask when you have ever linked it.
Add Hook up with Pockets
In case 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, once you go to your internet app, the online app appears like this:
Subsequent, click on on the “Join your pockets” button, and you may see it pops Metamask!
After you authorize your pockets, you may see this display screen:
And in case you go to your console, you may see it prints out your public tackle. In case you refresh your web page right here, you may see your pockets connection additionally sticks round.
Including .env variables
It’s essential 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 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, remember to add them in .gitignore
Creating an Alchemy app
Subsequent, head to Alchemy, register, 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 want the pockets’s personal key.
To entry it, open the MetaMask browser extension and click on on Account Particulars. You need to see your personal key right here; export it and duplicate it someplace secure.
Getting Began with Thirdweb
Superior! Now you can connect with a consumer’s pockets to examine in the event that they’re in your DAO! To hitch your DAO, the consumer 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 a part of your DAO!
However, there’s an issue. For us to mint NFTs, you need to write and deploy your personal NFT sensible contract. That is truly the place Thirdweb is available in clutch.
Thirdweb offers us a set of instruments to create all our sensible contracts with out writing any Solidity. You write no Solidity. All you should 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, and so they’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’ll create them with JavaScript. Additionally, thirdweb would not have a database; all of your information is saved on-chain.
Initialize Thirdweb SDK
Now, write scripts that allow you to initialize Thirdweb SDK. You may 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 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 () => {
attempt {
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).
It will 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 package deal.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’re going to get your app tackle after a while.
You will want this within the subsequent steps, so retailer it someplace secure.
You’ll now create and deploy an ERC-1155 contract to Rinkeby. That is principally the bottom module you may have to 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 exhibits up on OpenSea because the header.
With an ERC-1155, a number of individuals may be the holder of the identical NFT. On this case, your “membership NFT” is similar for everybody, so as an alternative 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 widespread method for instances 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 () => {
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, 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 remember to embrace that picture below scripts/belongings
. Ensure it is a PNG, JPG, or GIF for now and be certain it is a native picture — this would possibly not work in case you use an web hyperlink!
After you will have up to date the main points, run the next script:
node scripts/2-deploy-drop.js
Await the script to run; you must get an tackle 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 tackle of the editionDrop
contract, you may see you simply deployed a wise contract! The best half is that you simply personal this contract deployed out of your pockets. The “From” tackle can be your public tackle.
Be aware: Maintain the tackle of your
editionDrop
round; you may want it later! in case you ever lose it, you may all the time retrieve it from the thirdweb dashboard
One other factor that occurred right here is that Thirdweb routinely uploaded and pinned your assortment’s picture to IPFS. You may 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 Knowledge
Let’s truly 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 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("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 can even discover this in your thirdweb dashboard.
Then, you are establishing your precise NFT in your ERC-1155 utilizing createBatch
. It’s essential to arrange some properties:
identify
: The identify of your NFT.description
: The outline of your NFTpicture
: The picture on 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.
After 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 embrace the next properties:
-
startTime
is when customers are allowed to start out 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 worth of your NFT; in your case, 0 at no costwaitInSeconds
is the period of time between transactions; since you solely need individuals 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 modify the situations
After operating node scripts/4-set-claim-condition.js
, here is what you may get:
Letting customers mint their NFT
At this stage now, you may be checking two issues:
-
In case your consumer has a membership NFT, present them your “DAO Dashboard” display screen the place they will vote on proposals and see DAO-related information.
-
If the consumer 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, beneath 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 () => {
attempt {
const steadiness = await editionDrop.balanceOf(tackle, 0);
if (steadiness.gt(0)) {
setHasClaimedNFT(true);
console.log("🌟 this consumer has a membership NFT!");
} else {
setHasClaimedNFT(false);
console.log("😭 this consumer would not have a membership NFT.");
}
} catch (error) {
setHasClaimedNFT(false);
console.error("Did not get steadiness", 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 consumer has your NFT - Use
editionDrop.balanceOf(tackle, "0")
to examine if the consumer has our NFT.
In case 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 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 screen like this.
In case you click on on the Mint your nft (FREE) button, it ought to pop up in your MetaMask display screen to finish the transaction. Within the console, you must see the next.
As soon as it is completed minting, you must see Efficiently Minted!
in your console together with the Testnet OpenSea hyperlink. On testnets.opensea.io
, you may truly see NFTs minted on the testnet. If you head to your hyperlink, you may see one thing like this:
Present DAO Dashboard provided that the consumer owns the NFT
Lastly, simply above the ultimate return
block, add this examine to see if the consumer 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’ve got 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, 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:
Growth! It deployed a recent token contract. In case 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 routinely:
Then, head again to your pockets, scroll down, and increase!
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's",
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 need 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 () => {
attempt {
const walletAddresses = await editionDrop.historical past.getAllClaimerAddresses(0);
if (walletAddresses.size === 0) {
console.log(
"No NFTs have been claimed but; possibly get some buddies to say 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 must get one thing like this.
At present, 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, however it’s ineffective if individuals can’t use it to control something! What you’re going to do subsequent right here is about up a governance contract that lets individuals 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, 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 have to 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(
"did not 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("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 thing is about up. Now, you simply have to 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 a further " + 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);
}
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 individuals vote for it!"
);
} catch (error) {
console.error("did not create second proposal", error);
}
})();
It’s essential to replace the module addresses, and if you wish to replace the message of the proposal, you can too 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 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 online 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("did not 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, 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 consumer can’t vote once more!
Thirdweb not solely makes it very easy to deploy sensible contracts, however it additionally makes it very simple 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’ll discover all the info.
Rendering the proposals
Add the zero tackle import after your present imports:
import { AddressZero } from "@ethersproject/constants";
Go forward and exchange the code of if(hasClaimedNFT) { }
with the code here.
If you try your internet 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. Which means you may go and create extra tokens if you would like, which can freak out members of your DAO.
So, It’s greatest to revoke your “minting” position utterly. That means, 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);
}
})();
If you run this utilizing node scripts/11-revoke-roles.js. you may get:
Deal with fundamental unsupported community error
To acknowledge a connection exterior 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
perform:
if (tackle && (community?.[0].information.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 swap 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 modify networks.
Conclusion
You’ve completed it. You made it to the tip. On this article, you deployed your personal customized ERC-20 token and deployed your personal ERC-1155 NFT individuals can mint to hitch your DAO.
You additionally discovered to deploy your personal governance contract and treasury. Constructed a dapp that lets individuals 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.