Sıfırdan Merkezi Olmayan Otonom Organizasyon (DAO) Oluşturma
Merkezi Olmayan Otonom Kuruluşlar (DAO'lar), merkezi olmayan ekosistemin temel taşıdır. DAO'lar, akıllı sözleşmelerle yönetilen ve karar verme süreçleri merkezi olmayan bir şekilde yürütülen kuruluşlardır. Bu yazıda, sıfırdan bir DAO oluşturmak için gelişmiş Solidity kavramlarını inceleyeceğiz.

DAO Yapısına Genel Bakış
DAO'muz aşağıdaki bileşenlerden oluşacaktır
- DAO'nun kendisini temsil eden bir akıllı sözleşme.
- DAO içindeki oylama gücünü ve sahipliğini temsil eden bir belirteç.
- Teklifleri göndermek ve oylamak için bir teklif mekanizması.
- Fonları yönetmek ve onaylanan teklifleri yürütmek için bir hazine.
Bu öğreticiyi takip etmek için Solidity, Ethereum ve Truffle geliştirme ortamı hakkında temel bir anlayışa sahip olmalısınız.
1. Adım: DAO Jetonunu Oluşturma
Öncelikle, DAO'muz için yeni bir ERC20 belirteci oluşturalım. Bu belirteç, kuruluş içindeki oylama gücünü temsil etmek için kullanılacaktır.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract DAOToken is ERC20 {
constructor(uint256 initialSupply) ERC20("DAO Token", "DAO") {
_mint(msg.sender, initialSupply);
}
}
2. Adım: DAO Sözleşmesini Oluşturma
Ardından, ana DAO sözleşmesini oluşturalım. adlı yeni bir dosya oluşturun.DAO.sol
// SPDX-License-Identifier: MIT
prasgma solidity ^0.8.0;
import "./DAOToken.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract DAO is Ownable {
using EnumerableSet for EnumerableSet.AddressSet;
// The DAO token contract
DAOToken public daoToken;
// The minimum amount of tokens required to create a proposal
uint256 public constant MIN_PROPOSAL_THRESHOLD = 1000 * 10**18;
// The minimum amount of tokens required to vote on a proposal
uint256 public constant MIN_VOTING_THRESHOLD = 100 * 10**18;
// Proposal struct
struct Proposal {
uint256 id;
address proposer;
string description;
uint256 amount;
address payable recipient;
uint256 startTime;
uint256 endTime;
uint256 yesVotes;
uint256 noVotes;
EnumerableSet.AddressSet voters;
bool executed;
}
// Array of all proposals
Proposal[] public proposals;
// Mapping to check if an address has an active proposal
mapping(address => bool) public activeProposals;
// Event for a new proposal
event NewProposal(uint256 indexed proposalId, address indexed proposer, string description);
// Event for a proposal execution
event ProposalExecuted(uint256 indexed proposalId, address indexed proposer, address indexed recipient, uint256 amount);
constructor(DAOToken _daoToken) {
daoToken = _daoToken;
}
// Function to create a new proposal
function createProposal(string memory _description, uint256 _amount, address payable _recipient) external {
require(daoToken.balanceOf(msg.sender) >= MIN_PROPOSAL_THRESHOLD, "Insufficient tokens to create proposal");
require(!activeProposals[msg.sender], "You already have an active proposal");
Proposal memory newProposal = Proposal({
id: proposals.length,
proposer: msg.sender,
description: _description,
amount: _amount,
recipient: _recipient,
startTime: block.timestamp,
endTime: block.timestamp + 7 days,
yesVotes: 0,
noVotes: 0,
voters: new EnumerableSet.AddressSet(),
executed: false
});
proposals.push(newProposal);
activeProposals[msg.sender] = true;
emit NewProposal(newProposal.id, msg.sender, _description);
}
// Function to vote on a proposal
function vote(uint256 _proposalId, bool _support) external {
require(daoToken.balanceOf(msg.sender) >= MIN_VOTING_THRESHOLD, "Insufficient tokens to vote");
Proposal storage proposal = proposals[_proposalId];
require(block.timestamp >= proposal.startTime && block.timestamp <= proposal.endTime, "Invalid voting period");
require(!proposal.voters.contains(msg.sender), "You have already voted on this proposal");
uint256 voterWeight = daoToken.balanceOf(msg.sender);
if (_support) {
proposal.yesVotes += voterWeight;
} else {
proposal.noVotes += voterWeight;
}
proposal.voters.add(msg.sender);
}
// Function to execute a proposal
function executeProposal(uint256 _proposalId) external {
Proposal storage proposal = proposals[_proposalId];
require(!proposal.executed, "Proposal has already been executed");
require(block.timestamp > proposal.endTime, "Voting period is still ongoing");
require(proposal.yesVotes > proposal.noVotes, "Proposal has not reached majority support");
proposal.recipient.transfer(proposal.amount);
proposal.executed = true;
activeProposals[proposal.proposer] = false;
emit ProposalExecuted(_proposalId, proposal.proposer, proposal.recipient, proposal.amount);
}
// Function to withdraw funds from the DAO
function withdraw(uint256 _amount) external onlyOwner {
payable(owner()).transfer(_amount);
}
// Fallback function to accept Ether
receive() external payable {}
}
- DAO belirteç sözleşmesi içe aktarılır ve bir değişken olarak depolanır.
- Teklif kimliği, teklif sahibi, açıklama, miktar, alıcı ve oylama detayları gibi gerekli alanlarla bir teklif yapısı tanımlanır.
- Bir dizi, tüm teklifleri saklar ve bir eşleme, aktif teklifleri takip eder.
- Teklif oluşturma, oylama ve yürütme işlemlerini yürütmek için işlevler oluşturulur.
Artık DAO sözleşmesini oluşturduğumuza göre, onu dağıtalım ve işlevselliğini test edelim. Öncelikle sözleşmelerimiz için bir taşıma dosyası oluşturalım.
const DAOToken = artifacts.require("DAOToken"); const DAO = artifacts.require("DAO");
module.exports = async function (deployer) {
// Deploy the DAOToken contract with an initial supply of 1,000,000 tokens
await deployer.deploy(DAOToken, "1000000" + "0".repeat(18));
const daoTokenInstance = await DAOToken.deployed();
// Deploy the DAO contract with a reference to the DAOToken contract
await deployer.deploy(DAO, daoTokenInstance.address);
const daoInstance = await DAO.deployed();
};
const { assert } = require("chai");
const { expectRevert, time } = require("@openzeppelin/test-helpers");
const DAOToken = artifacts.require("DAOToken");
const DAO = artifacts.require("DAO");
contract("DAO", ([deployer, user1, user2, recipient]) => {
beforeEach(async () => {
this.daoToken = await DAOToken.new("1000000" + "0".repeat(18), { from: deployer });
this.dao = await DAO.new(this.daoToken.address, { from: deployer });
});
it("should create a proposal and vote on it", async () => {
// Transfer tokens to user1
await this.daoToken.transfer(user1, "1100" + "0".repeat(18), { from: deployer });
// User1 creates a proposal
await this.dao.createProposal("Fund project X", "100" + "0".repeat(18), recipient, {
from: user1,
});
// Check the proposal details
const proposal = await this.dao.proposals(0);
assert.equal(proposal.id, "0");
assert.equal(proposal.proposer, user1);
assert.equal(proposal.description, "Fund project X");
assert.equal(proposal.amount, "100" + "0".repeat(18));
assert.equal(proposal.recipient, recipient);
// User1 votes on the proposal
await this.dao.vote(0, true, { from: user1 });
// Check the voting results
assert.equal((await this.dao.proposals(0)).yesVotes, "1100" + "0".repeat(18));
assert.equal((await this.dao.proposals(0)).noVotes, "0");
// Fast-forward time to after the voting period
await time.increase(time.duration.days(8));
// Execute the proposal
await this.dao.executeProposal(0, { from: user1 });
// Check that the proposal has been executed
assert.equal((await this.dao.proposals(0)).executed, true);
});
it("should not allow a user with insufficient tokens to create a proposal", async () => {
// Try to create a proposal with insufficient tokens
await expectRevert(
this.dao.createProposal("Fund project X", "100" + "0".repeat(18), recipient, { from: user2 }),
"Insufficient tokens to create proposal"
);
});
// Add more tests as necessary
});
- Bir teklif oluşturmak ve üzerinde oy kullanmak.
- Yetersiz belirteçleri olan bir kullanıcının sağlanması teklif oluşturamaz. Aşağıdaki komutu kullanarak testleri çalıştırabilirsiniz:
Dağıtılan DAO'nuzla etkileşim kurmak için bir web arabirimi kullanabilirsiniz.
Web arayüzünün temel bileşenleri şunları içerebilir:
- DAO belirteci bakiyesini ve teklif listesini görüntüleyen bir pano.
- Yeni bir teklif oluşturmak için bir form.
- Mevcut tekliflere oy vermek için bir oylama arayüzü.
- Onaylanan teklifleri yürütmek için bir düğme.
Web 3.0 ve merkezi olmayan uygulamaların potansiyeli çok geniştir ve geliştiricilere internetin geleceğini şekillendirmek için heyecan verici fırsatlar sunar. Blok zinciri teknolojisinin gücünden yararlanarak, kullanıcıları güçlendiren ve merkezsizleşmeyi teşvik eden daha güvenli, şeffaf ve dayanıklı uygulamalar oluşturabiliriz.
Bir geliştirici olarak, merkezi olmayan ekosistemin büyümesine katkıda bulunma ve gerçek dünyadaki sorunları çözmek için yenilikçi çözümler oluşturma şansına sahipsiniz. Merkezi olmayan finans (DeFi) ve misli olmayan jetonlardan (NFT'ler) merkezi olmayan depolama ve kimlik yönetimine kadar web3 teknolojilerinin sunduğu sayısız olasılığı keşfetmenizi tavsiye ederim.