Rumah >Peranti teknologi >industri IT >Membina Ethereum Dapps: Mengundi dengan Token Kustom
mata teras
Jika anda keliru dengan ini, kod sumber lengkap boleh didapati di pangkalan kod.
undi dan cadangan
Kami akan menggunakan cadangan dan undi untuk mengundi. Kami memerlukan dua struktur baru:
<code>struct Proposal { string description; bool executed; int256 currentResult; uint8 typeFlag; // 1 = delete bytes32 target; // 提案目标的ID。例如,标志1,目标XXXXXX(哈希)表示删除submissions[hash]的提案 uint256 creationDate; uint256 deadline; mapping (address => bool) voters; Vote[] votes; address submitter; } Proposal[] public proposals; uint256 proposalCount = 0; event ProposalAdded(uint256 id, uint8 typeFlag, bytes32 hash, string description, address submitter); event ProposalExecuted(uint256 id); event Voted(address voter, bool vote, uint256 power, string justification); struct Vote { bool inSupport; address voter; string justification; uint256 power; }</code>Cadangan akan mengandungi peta pengundi untuk menghalang orang daripada mengundi dua kali pada satu cadangan, serta beberapa metadata lain yang harus jelas. Undian itu akan menjadi undi ya atau menentang dan akan mengingati sebab -sebab pengundi dan hak untuk mengundi -jumlah token yang mereka mahu gunakan untuk mengundi cadangan ini. Kami juga menambah pelbagai cadangan supaya kami dapat menyimpannya di suatu tempat, serta kaunter untuk mengira bilangan cadangan.
Sekarang mari kita membina fungsi sokongan mereka, bermula dengan fungsi pengundian:
<code>modifier tokenHoldersOnly() { require(token.balanceOf(msg.sender) >= 10**token.decimals()); _; } function vote(uint256 _proposalId, bool _vote, string _description, uint256 _votePower) tokenHoldersOnly public returns (int256) { require(_votePower > 0, "At least some power must be given to the vote."); require(uint256(_votePower) <= token.balanceOf(msg.sender), "Vote power exceeds token balance."); Proposal storage p = proposals[_proposalId]; require(p.executed == false, "Proposal must not have been executed already."); require(p.deadline > now, "Proposal must not have expired."); require(p.voters[msg.sender] == false, "User must not have already voted."); uint256 voteid = p.votes.length++; Vote storage pvote = p.votes[voteid]; pvote.inSupport = _vote; pvote.justification = _description; pvote.voter = msg.sender; pvote.power = _votePower; p.voters[msg.sender] = true; p.currentResult = (_vote) ? p.currentResult + int256(_votePower) : p.currentResult - int256(_votePower); token.increaseLockedAmount(msg.sender, _votePower); emit Voted(msg.sender, _vote, _votePower, _description); return p.currentResult; }</code>Nota Pengubahsuaian Fungsi: Dengan menambahkan pengubah ini ke kontrak kami, kami dapat menambahkannya ke mana -mana fungsi masa depan dan pastikan hanya pemegang token yang dapat melaksanakan fungsi tersebut. Ini adalah pemeriksaan keselamatan yang boleh diguna semula!
Fungsi pengundian melakukan beberapa pemeriksaan sanitari, seperti hak pengundian adalah positif, pengundi mempunyai token yang cukup untuk benar -benar mengundi, dll. Kami kemudian mengambil cadangan dari storan dan pastikan ia tidak tamat tempoh atau dilaksanakan. Ia tidak masuk akal untuk mengundi atas cadangan yang lengkap. Kami juga perlu memastikan bahawa orang ini belum mengundi. Kami boleh membenarkan hak mengundi diubah, tetapi ini boleh meletakkan Daos dalam menghadapi beberapa kelemahan, seperti orang yang mengeluarkan undi mereka pada saat -saat akhir, dll. Mungkin calon untuk versi masa depan?
Kami kemudian mendaftarkan undi baru ke dalam cadangan, menukar hasil semasa untuk mencari skor, dan akhirnya mengeluarkan acara pengundian. Tetapi apakah token.increaselockedamount?
Logik ini meningkatkan bilangan token terkunci untuk pengguna. Fungsi ini hanya boleh dilaksanakan oleh pemilik kontrak token (kali ini diharapkan menjadi DAO) dan akan menghalang pengguna daripada menghantar lebih daripada jumlah terkunci yang didaftarkan ke akaun mereka. Kunci ini dikeluarkan selepas cadangan gagal atau dilaksanakan.
Sekarang mari kita tulis fungsi untuk menyampaikan penyertaan padam.
mengundi untuk memadam dan menyenaraih hitam
Di bahagian pertama siri ini, kami merancang tiga fungsi penghapusan kemasukan:
Menghapus lima penyertaan untuk satu alamat akan menghasilkan senarai hitam.
mari kita lihat bagaimana kita melakukan ini sekarang. Pertama, padamkan fungsi:
<code>struct Proposal { string description; bool executed; int256 currentResult; uint8 typeFlag; // 1 = delete bytes32 target; // 提案目标的ID。例如,标志1,目标XXXXXX(哈希)表示删除submissions[hash]的提案 uint256 creationDate; uint256 deadline; mapping (address => bool) voters; Vote[] votes; address submitter; } Proposal[] public proposals; uint256 proposalCount = 0; event ProposalAdded(uint256 id, uint8 typeFlag, bytes32 hash, string description, address submitter); event ProposalExecuted(uint256 id); event Voted(address voter, bool vote, uint256 power, string justification); struct Vote { bool inSupport; address voter; string justification; uint256 power; }</code>
Selepas mengemukakan, cadangan itu ditambah ke senarai cadangan dan entri sasaran dicatatkan oleh hash entri. Simpan keterangan dan tambahkan beberapa nilai lalai dan hitung tarikh akhir berdasarkan jenis cadangan. Acara tambahan dikeluarkan dan jumlah cadangan meningkat.
Seterusnya, mari kita lihat bagaimana untuk melaksanakan cadangan itu. Untuk dikuatkuasakan, cadangan mesti mempunyai undi yang mencukupi dan mesti melebihi tarikh akhir. Fungsi pelaksanaan akan menerima ID cadangan untuk dilaksanakan. Tidak ada cara mudah untuk mempunyai EVM melaksanakan semua cadangan yang belum selesai sekaligus. Mungkin terdapat terlalu banyak cadangan yang akan dilaksanakan dan mereka boleh membuat perubahan ketara terhadap data dalam DAO, yang mungkin melebihi had gas blok Ethereum, mengakibatkan kegagalan transaksi. Lebih mudah untuk membina fungsi pelaksanaan manual yang boleh dipanggil oleh sesiapa sahaja yang mematuhi peraturan yang jelas, supaya masyarakat dapat memberi tumpuan kepada cadangan yang perlu dilaksanakan.
<code>modifier tokenHoldersOnly() { require(token.balanceOf(msg.sender) >= 10**token.decimals()); _; } function vote(uint256 _proposalId, bool _vote, string _description, uint256 _votePower) tokenHoldersOnly public returns (int256) { require(_votePower > 0, "At least some power must be given to the vote."); require(uint256(_votePower) <= token.balanceOf(msg.sender), "Vote power exceeds token balance."); Proposal storage p = proposals[_proposalId]; require(p.executed == false, "Proposal must not have been executed already."); require(p.deadline > now, "Proposal must not have expired."); require(p.voters[msg.sender] == false, "User must not have already voted."); uint256 voteid = p.votes.length++; Vote storage pvote = p.votes[voteid]; pvote.inSupport = _vote; pvote.justification = _description; pvote.voter = msg.sender; pvote.power = _votePower; p.voters[msg.sender] = true; p.currentResult = (_vote) ? p.currentResult + int256(_votePower) : p.currentResult - int256(_votePower); token.increaseLockedAmount(msg.sender, _votePower); emit Voted(msg.sender, _vote, _votePower, _description); return p.currentResult; }</code>
kami mendapat cadangan dengan IDnya, periksa bahawa ia memenuhi keperluan yang tidak diutam Mengeluarkan acara baru (tambahkan ke bahagian atas kontrak). Panggilan menegaskan berfungsi dengan cara yang sama seperti pernyataan yang memerlukan di sana: menegaskan biasanya digunakan untuk "menegaskan" hasilnya adalah benar. Memerlukan digunakan untuk prasyarat. Secara fungsional mereka adalah sama, perbezaannya adalah bahawa pernyataan menegaskan tidak dapat menerima parameter mesej untuk mengendalikan situasi di mana mereka gagal. Fungsi ini berakhir dengan membuka token untuk semua undi dalam cadangan.
Kami boleh menambah jenis cadangan lain menggunakan kaedah yang sama, tetapi pertama, mari kita mengemas kini fungsi penghapusan untuk melarang pengguna dengan lima atau lebih pemadaman pada akaun mereka: ini bermakna mereka sentiasa mengemukakan kandungan yang dibantah oleh masyarakat. Mari kita kemas kini fungsi penghapusan:
<code>struct Proposal { string description; bool executed; int256 currentResult; uint8 typeFlag; // 1 = delete bytes32 target; // 提案目标的ID。例如,标志1,目标XXXXXX(哈希)表示删除submissions[hash]的提案 uint256 creationDate; uint256 deadline; mapping (address => bool) voters; Vote[] votes; address submitter; } Proposal[] public proposals; uint256 proposalCount = 0; event ProposalAdded(uint256 id, uint8 typeFlag, bytes32 hash, string description, address submitter); event ProposalExecuted(uint256 id); event Voted(address voter, bool vote, uint256 power, string justification); struct Vote { bool inSupport; address voter; string justification; uint256 power; }</code>
Ini lebih baik. Secara automatik disenarai hitam dan dipadam lima kali. Adalah tidak adil untuk tidak memberikan alamat yang disenarai hitam peluang untuk menebus. Kami juga perlu menentukan fungsi Blacklist itu sendiri. Mari kita lakukan kedua -dua perkara ini dan tetapkan yuran untuk membatalkan senarai hitam kepada, contohnya, 0.05 Ether.
<code>modifier tokenHoldersOnly() { require(token.balanceOf(msg.sender) >= 10**token.decimals()); _; } function vote(uint256 _proposalId, bool _vote, string _description, uint256 _votePower) tokenHoldersOnly public returns (int256) { require(_votePower > 0, "At least some power must be given to the vote."); require(uint256(_votePower) <= token.balanceOf(msg.sender), "Vote power exceeds token balance."); Proposal storage p = proposals[_proposalId]; require(p.executed == false, "Proposal must not have been executed already."); require(p.deadline > now, "Proposal must not have expired."); require(p.voters[msg.sender] == false, "User must not have already voted."); uint256 voteid = p.votes.length++; Vote storage pvote = p.votes[voteid]; pvote.inSupport = _vote; pvote.justification = _description; pvote.voter = msg.sender; pvote.power = _votePower; p.voters[msg.sender] = true; p.currentResult = (_vote) ? p.currentResult + int256(_votePower) : p.currentResult - int256(_votePower); token.increaseLockedAmount(msg.sender, _votePower); emit Voted(msg.sender, _vote, _votePower, _description); return p.currentResult; }</code>
Sila ambil perhatian bahawa token untuk akaun yang disenarai hitam akan dikunci sehingga mereka menghantar bayaran untuk membatalkan senarai hitam.
jenis undi lain
Cuba menulis cadangan lain berdasarkan inspirasi untuk fungsi yang kami tulis di atas. Untuk spoiler, lihat asas kod GitHub projek dan salin kod akhir dari sana. Untuk keringkasan, mari kita beralih ke fungsi lain yang masih ada di DAO.
akhir bab
Apabila had masa atau bab cerita dicapai, sudah tiba masanya untuk mengakhiri cerita. Selepas tarikh, sesiapa sahaja boleh memanggil fungsi akhir, yang akan membolehkan dividen ditarik balik. Pertama, kita memerlukan harta Storydao baru dan acara:
<code>modifier memberOnly() { require(whitelist[msg.sender]); require(!blacklist[msg.sender]); _; } function proposeDeletion(bytes32 _hash, string _description) memberOnly public { require(submissionExists(_hash), "Submission must exist to be deletable"); uint256 proposalId = proposals.length++; Proposal storage p = proposals[proposalId]; p.description = _description; p.executed = false; p.creationDate = now; p.submitter = msg.sender; p.typeFlag = 1; p.target = _hash; p.deadline = now + 2 days; emit ProposalAdded(proposalId, 1, _hash, _description, msg.sender); proposalCount = proposalId + 1; } function proposeDeletionUrgent(bytes32 _hash, string _description) onlyOwner public { require(submissionExists(_hash), "Submission must exist to be deletable"); uint256 proposalId = proposals.length++; Proposal storage p = proposals[proposalId]; p.description = _description; p.executed = false; p.creationDate = now; p.submitter = msg.sender; p.typeFlag = 1; p.target = _hash; p.deadline = now + 12 hours; emit ProposalAdded(proposalId, 1, _hash, _description, msg.sender); proposalCount = proposalId + 1; } function proposeDeletionUrgentImage(bytes32 _hash, string _description) onlyOwner public { require(submissions[_hash].image == true, "Submission must be existing image"); uint256 proposalId = proposals.length++; Proposal storage p = proposals[proposalId]; p.description = _description; p.executed = false; p.creationDate = now; p.submitter = msg.sender; p.typeFlag = 1; p.target = _hash; p.deadline = now + 4 hours; emit ProposalAdded(proposalId, 1, _hash, _description, msg.sender); proposalCount = proposalId + 1; }</code>
Kemudian, mari kita bina fungsi:
<code>function executeProposal(uint256 _id) public { Proposal storage p = proposals[_id]; require(now >= p.deadline && !p.executed); if (p.typeFlag == 1 && p.currentResult > 0) { assert(deleteSubmission(p.target)); } uint256 len = p.votes.length; for (uint i = 0; i < len; i++) { token.decreaseLockedAmount(p.votes[i].voter, p.votes[i].power); } p.executed = true; emit ProposalExecuted(_id); }</code>
mudah: Ia melumpuhkan cerita selepas menghantar yuran yang dikumpulkan kepada pemilik dan menghantar acara. Tetapi pada hakikatnya, ini tidak benar -benar mengubah keadaan keseluruhan DAO: fungsi lain tidak bertindak balas terhadapnya. Oleh itu, mari kita bina pengubah lain:
<code>function deleteSubmission(bytes32 hash) internal returns (bool) { require(submissionExists(hash), "Submission must exist to be deletable."); Submission storage sub = submissions[hash]; sub.exists = false; deletions[submissions[hash].submitter] += 1; if (deletions[submissions[hash].submitter] >= 5) { blacklistAddress(submissions[hash].submitter); } emit SubmissionDeleted( sub.index, sub.content, sub.image, sub.submitter ); nonDeletedSubmissions -= 1; return true; }</code>
maka kami menambah pengubah ini ke semua fungsi kecuali penarikan balik, seperti yang ditunjukkan di bawah:
<code>function blacklistAddress(address _offender) internal { require(blacklist[_offender] == false, "Can't blacklist a blacklisted user :/"); blacklist[_offender] == true; token.increaseLockedAmount(_offender, token.getUnlockedAmount(_offender)); emit Blacklisted(_offender, true); } function unblacklistMe() payable public { unblacklistAddress(msg.sender); } function unblacklistAddress(address _offender) payable public { require(msg.value >= 0.05 ether, "Unblacklisting fee"); require(blacklist[_offender] == true, "Can't unblacklist a non-blacklisted user :/"); require(notVoting(_offender), "Offender must not be involved in a vote."); withdrawableByOwner = withdrawableByOwner.add(msg.value); blacklist[_offender] = false; token.decreaseLockedAmount(_offender, token.balanceOf(_offender)); emit Blacklisted(_offender, false); } function notVoting(address _voter) internal view returns (bool) { for (uint256 i = 0; i < proposals.length; i++) { if (proposals[i].executed == false && proposals[i].voters[_voter] == true) { return false; } } return true; }</code>
Jika masih ada token yang tinggal di DAO, mari kita bawa mereka kembali dan mengambil pemilikan token tersebut supaya kita dapat menggunakannya kemudian untuk cerita lain:
<code>bool public active = true; event StoryEnded();</code>Fungsi
UnlockMytokens digunakan untuk membuka kunci semua token terkunci yang pengguna boleh mengunci. Ini tidak sepatutnya berlaku, dan fungsi ini harus dikeluarkan dengan banyak ujian.
DIP Distribution dan pengeluaran dividen
Sekarang cerita itu berakhir, yuran yang dikenakan untuk penyerahan perlu diperuntukkan kepada semua pemegang token. Kami boleh menggunakan semula senarai putih kami untuk menandakan semua orang yang telah mengeluarkan yuran mereka:
<code>function endStory() storyActive external { withdrawToOwner(); active = false; emit StoryEnded(); }</code>
Jika dividen ini tidak ditarik balik dalam had masa tertentu, pemilik boleh mendapatkan bahagian yang tinggal:
<code>modifier storyActive() { require(active == true); _; }</code>
Sebagai kerja rumah, pertimbangkan betapa mudahnya atau sukar untuk menggunakan semula kontrak pintar yang digunakan ini, jelaskan datanya, simpan token di kolam dan mulakan semula bab lain dari sini tanpa memulihkan semula. Cuba lakukan ini sendiri dan ikuti asas kod untuk kemas kini masa depan yang meliputi siri ini! Juga pertimbangkan insentif tambahan: Mungkin bilangan token dalam akaun akan menjejaskan dividen yang mereka terima dari akhir cerita? Imajinasi anda tidak terhingga!
isu penyebaran
Memandangkan kontrak kami kini agak besar, menggunakan dan/atau menguji ia mungkin melebihi had gas blok Ethereum. Inilah yang mengehadkan aplikasi besar daripada menyebarkan ke rangkaian Ethereum. Untuk menggunakannya, cuba gunakan pengoptimum kod semasa penyusunan dengan menukar fail truffle.js untuk memasukkan tetapan SOLC yang dioptimumkan seperti berikut:
<code>struct Proposal { string description; bool executed; int256 currentResult; uint8 typeFlag; // 1 = delete bytes32 target; // 提案目标的ID。例如,标志1,目标XXXXXX(哈希)表示删除submissions[hash]的提案 uint256 creationDate; uint256 deadline; mapping (address => bool) voters; Vote[] votes; address submitter; } Proposal[] public proposals; uint256 proposalCount = 0; event ProposalAdded(uint256 id, uint8 typeFlag, bytes32 hash, string description, address submitter); event ProposalExecuted(uint256 id); event Voted(address voter, bool vote, uint256 power, string justification); struct Vote { bool inSupport; address voter; string justification; uint256 power; }</code>
Ini akan menjalankan pengoptimum 200 kali pada kod untuk mencari kawasan yang dapat disempitkan, dipadam, atau dicabut sebelum penggunaan, yang harus mengurangkan kos penempatan dengan ketara.
Kesimpulan
Ini berakhir pembangunan DAO terperinci kami - tetapi kursus belum berakhir! Kami masih perlu membina dan menggunakan UI untuk cerita ini. Mujurlah, membina hujung depan lebih mudah kerana backend sepenuhnya dihoskan di blok block. Mari kita lihat ini di bahagian terakhir siri ini.
Soalan -soalan yang sering ditanya mengenai membina Ethereum Dapps dan mengundi dengan token tersuai
Pengundian Blockchain adalah sistem pengundian yang terdesentralisasi yang menggunakan ketelusan dan keselamatan teknologi blockchain. Secara teorinya, ia harus berfungsi dengan sempurna, tetapi dalam praktiknya ia sering menghadapi cabaran. Proses pengundian melibatkan membuat kontrak pintar di blok Ethereum, dan setiap undi adalah transaksi yang dapat disahkan. Walau bagaimanapun, isu -isu seperti tidak mahu dikenali pengundi, manipulasi mengundi, dan kerumitan teknikal menggunakan platform blockchain mungkin menghalang pelaksanaan sebenar mereka.
DAO (Organisasi Autonomi Desentralisasi) Mekanisme pengundian adalah sistem yang membolehkan pemegang token di DAO untuk mengundi atas cadangan berdasarkan pemilikan token mereka. Mekanisme yang paling biasa termasuk pengundian majoriti mudah, yang diterima jika cadangan itu menerima lebih daripada 50% undi, dan pengundian sekunder, di mana kos mengundi pelbagai undi mengenai cadangan itu meningkat secara eksponen.
Tadbir urus dalam token yang selamat biasanya dikendalikan melalui sistem pengundian di mana pemegang token dapat mengundi mengenai pelbagai aspek projek. Ini mungkin termasuk keputusan mengenai pembangunan projek, ekonomi token, dan juga perubahan dalam sistem tadbir urus itu sendiri. Hak pengundian pemegang token biasanya berkadar dengan bilangan token yang mereka pegang.
Menubuhkan tadbir urus DAO melibatkan mewujudkan kontrak pintar di blok Ethereum yang menggariskan peraturan organisasi, termasuk hak mengundi dan mekanisme cadangan. Kontrak ini kemudiannya dikerahkan pada blockchain dan token yang mewakili hak mengundi diagihkan kepada ahli. Ahli kemudian boleh mencadangkan dan mengundi perubahan kepada organisasi.
Memegang token tadbir urus DAO mungkin berisiko kerana ketidaktentuan kriptografi dan ketidakpastian pengawalseliaan di sekitar DAO. Sebagai contoh, Suruhanjaya Perdagangan Niaga Hadapan Komoditi (CFTC) memberi amaran bahawa menggunakan token DAO untuk pengundian boleh dianggap sebagai bentuk manipulasi pasaran. Di samping itu, pemegang token mungkin kehilangan pelaburan mereka jika DAO tidak diuruskan atau menjadi mangsa serangan penggodam.
Membuat token tersuai untuk undi di Ethereum Dapp melibatkan menulis dan menggunakan kontrak pintar di blok Ethereum. Kontrak ini mentakrifkan sifat -sifat token, seperti namanya, simbol, dan jumlah bekalan. Sebaik sahaja kontrak dikerahkan, token boleh diedarkan kepada pengguna, dan pengguna kemudian boleh menggunakannya untuk mengundi mengenai cadangan di DAPP.
Pengundian Blockchain menawarkan pelbagai manfaat, termasuk ketelusan, keselamatan dan kebolehubahan. Undian direkodkan sebagai urus niaga pada blok block, menjadikannya telus dan dapat disahkan. Sifat blockchain yang terdesentralisasi juga menjadikannya sukar bagi mana -mana pihak untuk memanipulasi proses pengundian.
Oleh kerana pengundi tidak mahu namanya disiarkan dalam pengundian blockchain boleh mencabar kerana sifat telus transaksi blockchain. Walau bagaimanapun, teknik seperti bukti sifar pengetahuan boleh digunakan untuk mengesahkan kesahihan pengundi tanpa mendedahkan identiti pengundi.
Melaksanakan pengundian blockchain boleh mencabar kerana kerumitan teknikal, ketidakpastian pengawalseliaan dan risiko keselamatan yang berpotensi. Pengguna perlu biasa dengan teknologi blockchain untuk mengambil bahagian dalam proses pengundian, dan pengawal selia mungkin menyatakan kebimbangan mengenai legitimasi dan keselamatan sistem pengundian blockchain.
Mengurangkan risiko yang berkaitan dengan token tadbir urus DAO termasuk pengurusan yang teliti terhadap DAOS, langkah -langkah keselamatan menyeluruh, dan mengawasi perkembangan pengawalseliaan pada setiap masa. Ia juga penting untuk mempelbagaikan portfolio anda dan tidak melabur lebih daripada yang anda mampu.
Atas ialah kandungan terperinci Membina Ethereum Dapps: Mengundi dengan Token Kustom. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!