Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DAO dapp #18

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
/>

<!-- META -->
<title>My DAO</title>
<title>My CokoDAO</title>
<meta
name="description"
content="Check out my DAO built with @_buildspace & @thirdweb_!"
Expand Down
41 changes: 41 additions & 0 deletions scripts/1-initialize-sdk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import ethers from "ethers";

// Importing and configuring our .env file that we use to securely store our environment variables
import dotenv from "dotenv";
dotenv.config();

// Some quick checks to make sure our .env is working.
if (!process.env.PRIVATE_KEY || process.env.PRIVATE_KEY === "") {
console.log("🛑 Private key not found.");
}

if (!process.env.ALCHEMY_API_URL || process.env.ALCHEMY_API_URL === "") {
console.log("🛑 Alchemy API URL not found.");
}

if (!process.env.WALLET_ADDRESS || process.env.WALLET_ADDRESS === "") {
console.log("🛑 Wallet Address not found.");
}

const sdk = new ThirdwebSDK(
new ethers.Wallet(
// Your wallet private key. ALWAYS KEEP THIS PRIVATE, DO NOT SHARE IT WITH ANYONE, add it to your .env file and do not commit that file to github!
process.env.PRIVATE_KEY,
// RPC URL, we'll use our Alchemy API URL from our .env file.
ethers.getDefaultProvider(process.env.ALCHEMY_API_URL),
),
);

(async () => {
try {
const address = await sdk.getSigner().getAddress();
console.log("SDK initialized by address:", address)
} catch (err) {
console.error("Failed to get apps from the sdk", err);
process.exit(1);
}
})();

// We are exporting the initialized thirdweb SDK so that we can use it in our other scripts
export default sdk;
73 changes: 73 additions & 0 deletions scripts/10-create-vote-proposals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import sdk from "./1-initialize-sdk.js";
import { ethers } from "ethers";

// This is our governance contract.
const vote = sdk.getVote("0x74FB3B7259CE850fA3A2EED3Bf9F610fC9756164");

// This is our ERC-20 contract.
const token = sdk.getToken("0x6B8f666c5F843056DEfA2ef8124A562E5496d141");

(async () => {
try {
// Create proposal to mint 420,000 new token to the treasury.
const amount = 420_000;
const description = "Should the DAO mint an additional " + amount + " tokens into the treasury?";
const executions = [
{
// Our token contract that actually executes the mint.
toAddress: token.getAddress(),
// Our nativeToken is ETH. nativeTokenValue is the amount of ETH we want
// to send in this proposal. In this case, we're sending 0 ETH.
// We're just minting new tokens to the treasury. So, set to 0.
nativeTokenValue: 0,
// We're doing a mint! And, we're minting to the vote, which is
// acting as our treasury.
// in this case, we need to use ethers.js to convert the amount
// to the correct format. This is because the amount it requires is in wei.
transactionData: token.encoder.encode(
"mintTo", [
vote.getAddress(),
ethers.utils.parseUnits(amount.toString(), 18),
]
),
}
];

await vote.propose(description, executions);

console.log("✅ Successfully created proposal to mint tokens");
} catch (error) {
console.error("failed to create first proposal", error);
process.exit(1);
}

try {
// Create proposal to transfer ourselves 6,900 tokens for being awesome.
const amount = 6_900;
const description = "Should the DAO transfer " + amount + " tokens from the treasury to " +
process.env.WALLET_ADDRESS + " for being awesome?";
const executions = [
{
// Again, we're sending ourselves 0 ETH. Just sending our own token.
nativeTokenValue: 0,
transactionData: token.encoder.encode(
// We're doing a transfer from the treasury to our wallet.
"transfer",
[
process.env.WALLET_ADDRESS,
ethers.utils.parseUnits(amount.toString(), 18),
]
),
toAddress: token.getAddress(),
},
];

await vote.propose(description, executions);

console.log(
"✅ Successfully created proposal to reward ourselves from the treasury, let's hope people vote for it!"
);
} catch (error) {
console.error("failed to create second proposal", error);
}
})();
23 changes: 23 additions & 0 deletions scripts/11-revoke-roles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import sdk from "./1-initialize-sdk.js";

const token = sdk.getToken("0x6B8f666c5F843056DEfA2ef8124A562E5496d141");

(async () => {
try {
// Log the current roles.
const allRoles = await token.roles.getAll();

console.log("👀 Roles that exist right now:", allRoles);

// Revoke all the superpowers your wallet had over the ERC-20 contract.
await token.roles.setAll({ admin: [], minter: [] });
console.log(
"🎉 Roles after revoking ourselves",
await token.roles.getAll()
);
console.log("✅ Successfully revoked our superpowers from the ERC-20 contract");

} catch (error) {
console.error("Failed to revoke ourselves from the DAO trasury", error);
}
})();
37 changes: 37 additions & 0 deletions scripts/2-deploy-drop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { AddressZero } from "@ethersproject/constants";
import sdk from "./1-initialize-sdk.js";
import { readFileSync } from "fs";

(async () => {
try {
const editionDropAddress = await sdk.deployer.deployEditionDrop({
// The collection's name, ex. CryptoPunks
name: "CokoDAO Membership",
// A description for the collection.
description: "A DAO for fans of Coko.",
// The image that will be held on our NFT! The fun part :).
image: readFileSync("scripts/assets/lotsofdogs.jpg"),
// We need to pass in the address of the person who will be receiving the proceeds from sales of nfts in the contract.
// We're planning on not charging people for the drop, so we'll pass in the 0x0 address
// you can set this to your own wallet address if you want to charge for the drop.
primary_sale_recipient: AddressZero,
});

// this initialization returns the address of our contract
// we use this to initialize the contract on the thirdweb sdk
const editionDrop = sdk.getEditionDrop(editionDropAddress);

// with this, we can get the metadata of our contract
const metadata = await editionDrop.metadata.get();

console.log(
"✅ Successfully deployed editionDrop contract, address:",
editionDropAddress,
);
console.log("✅ editionDrop metadata:", metadata);
} catch (error) {
console.log("failed to deploy editionDrop contract", error);
}
})();

// edition drop = 0x6288757CC1d20E19d48Fc44C99Eb222C3A2cEAD5
19 changes: 19 additions & 0 deletions scripts/3-config-nft.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sdk from "./1-initialize-sdk.js";
import { readFileSync } from "fs";

const editionDrop = sdk.getEditionDrop("0x6288757CC1d20E19d48Fc44C99Eb222C3A2cEAD5");

(async () => {
try {
await editionDrop.createBatch([
{
name: "Cutest Flower Coko",
description: "This NFT will give you access to CokoDAO!",
image: readFileSync("scripts/assets/coko_flower.jpg"),
},
]);
console.log("✅ Successfully created a new NFT in the drop!");
} catch (error) {
console.error("failed to create the new NFT", error);
}
})();
29 changes: 29 additions & 0 deletions scripts/4-set-claim-condition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import sdk from "./1-initialize-sdk.js";
import { MaxUint256 } from "@ethersproject/constants";

const editionDrop = sdk.getEditionDrop("0x6288757CC1d20E19d48Fc44C99Eb222C3A2cEAD5");

(async () => {
try {
// We define our claim conditions, this is an array of objects because
// we can have multiple phases starting at different times if we want to
const claimConditions = [{
// When people are gonna be able to start claiming the NFTs (now)
startTime: new Date(),
// The maximum number of NFTs that can be claimed.
maxQuantity: 50_000,
// The price of our NFT (free)
price: 0,
// The amount of NFTs people can claim in one transaction.
quantityLimitPerTransaction: 1,
// We set the wait between transactions to MaxUint256, which means
// people are only allowed to claim once.
waitInSeconds: MaxUint256,
}]

await editionDrop.claimConditions.set("0", claimConditions);
console.log("✅ Sucessfully set claim condition!");
} catch (error) {
console.error("Failed to set claim condition", error);
}
})();
25 changes: 25 additions & 0 deletions scripts/5-deploy-token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AddressZero } from "@ethersproject/constants";
import sdk from "./1-initialize-sdk.js";

(async () => {
try {
// Deploy a standard ERC-20 contract.
const tokenAddress = await sdk.deployer.deployToken({
// What's your token's name? Ex. "Ethereum"
name: "CokoDAO Governance Token",
// What's your token's symbol? Ex. "ETH"
symbol: "COKO",
// This will be in case we want to sell our token,
// because we don't, we set it to AddressZero again.
primary_sale_recipient: AddressZero,
});
console.log(
"✅ Successfully deployed token module, address:",
tokenAddress,
);
} catch (error) {
console.error("failed to deploy token module", error);
}
})();

//TOKEN ADDRESS 0x6B8f666c5F843056DEfA2ef8124A562E5496d141
19 changes: 19 additions & 0 deletions scripts/6-print-money.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sdk from "./1-initialize-sdk.js";

// This is the address of our ERC-20 contract printed out in the step before.
const token = sdk.getToken("0x6B8f666c5F843056DEfA2ef8124A562E5496d141");

(async () => {
try {
// What's the max supply you want to set? 1,000,000 is a nice number!
const amount = 1000000;
// Interact with your deployed ERC-20 contract and mint the tokens!
await token.mint(amount);
const totalSupply = await token.totalSupply();

// Print out how many of our token's are out there now!
console.log("✅ There now is", totalSupply.displayValue, "$COKO in circulation");
} catch (error) {
console.error("Failed to print money", error);
}
})();
44 changes: 44 additions & 0 deletions scripts/7-airdrop-token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import sdk from "./1-initialize-sdk.js";

// This is the address to our ERC-1155 membership NFT contract.
const editionDrop = sdk.getEditionDrop("0x6288757CC1d20E19d48Fc44C99Eb222C3A2cEAD5");

// This is the address to our ERC-20 token contract.
const token = sdk.getToken("0x6B8f666c5F843056DEfA2ef8124A562E5496d141");

(async () => {
try {
// Grab all the addresses of people who own our membership NFT,
// which has a tokenId of 0.
const walletAddresses = await editionDrop.history.getAllClaimerAddresses(0);

if (walletAddresses.length === 0) {
console.log(
"No NFTs have been claimed yet, maybe get some friends to claim your free NFTs!",
);
process.exit(0);
}

// Loop through the array of addresses.
const airdropTargets = walletAddresses.map((address) => {
// Pick a random # between 1000 and 10000.
const randomAmount = Math.floor(Math.random() * (10000 - 1000 + 1) + 1000);
console.log("✅ Going to airdrop", randomAmount, "tokens to", address);

// Set up the target.
const airdropTarget = {
toAddress: address,
amount: randomAmount,
};

return airdropTarget;
});

// Call transferBatch on all our airdrop targets.
console.log("🌈 Starting airdrop...");
await token.transferBatch(airdropTargets);
console.log("✅ Successfully airdropped tokens to all the holders of the NFT!");
} catch (err) {
console.error("Failed to airdrop tokens", err);
}
})();
42 changes: 42 additions & 0 deletions scripts/8-deploy-vote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import sdk from "./1-initialize-sdk.js";

(async () => {
try {
const voteContractAddress = await sdk.deployer.deployVote({
// Give your governance contract a name.
name: "My amazing DAO",

// This is the location of our governance token, our ERC-20 contract!
voting_token_address: "0x6B8f666c5F843056DEfA2ef8124A562E5496d141",

// These parameters are specified in number of blocks.
// Assuming block time of around 13.14 seconds (for Ethereum)

// After a proposal is created, when can members start voting?
// For now, we set this to immediately.
voting_delay_in_blocks: 0,

// How long do members have to vote on a proposal when it's created?
// we will set it to 1 day = 6570 blocks
voting_period_in_blocks: 6570,

// The minimum % of the total supply that need to vote for
// the proposal to be valid after the time for the proposal has ended.
voting_quorum_fraction: 0,

// What's the minimum # of tokens a user needs to be allowed to create a proposal?
// I set it to 0. Meaning no tokens are required for a user to be allowed to
// create a proposal.
proposal_token_threshold: 0,
});

console.log(
"✅ Successfully deployed vote contract, address:",
voteContractAddress,
);
} catch (err) {
console.error("Failed to deploy vote contract", err);
}
})();

// voting address 0x74FB3B7259CE850fA3A2EED3Bf9F610fC9756164
Loading