您好,登錄后才能下訂單哦!
這篇文章主要介紹“以太坊構(gòu)建DApps中怎么使用定制代幣進(jìn)行投票”,在日常操作中,相信很多人在以太坊構(gòu)建DApps中怎么使用定制代幣進(jìn)行投票問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”以太坊構(gòu)建DApps中怎么使用定制代幣進(jìn)行投票”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
我們將發(fā)布Votes并投票。這需要兩個新的結(jié)構(gòu):
struct Proposal { string description; bool executed; int256 currentResult; uint8 typeFlag; // 1 = delete bytes32 target; // ID of the proposal target. I.e. flag 1, target XXXXXX (hash) means proposal to delete 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; }
提案將對選民進(jìn)行映射,以防止人們對提案進(jìn)行兩次投票,以及其他一些應(yīng)該不言自明的元數(shù)據(jù)。投票將是一個是或否投票,并將記住選民以及他們以某種方式投票的理由,以及投票權(quán)——他們希望投入該投票的代幣數(shù)量。我們還添加了一系列Proposals
,以便我們可以將它們存儲在某個地方,并提供一個計數(shù)器來計算有多少提案。
讓我們現(xiàn)在構(gòu)建他們的附屬函數(shù),從投票函數(shù)開始:
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), "Voter must have enough tokens to cover the power cost."); 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; }
注意函數(shù)修飾符:通過將該修飾符添加到我們的合約中,我們可以將它附加到任何將來的函數(shù),并確保只有令牌持有者才能執(zhí)行該函數(shù)。這是一個可重復(fù)使用的安全檢查!
投票功能做了一些健壯性檢查,例如投票權(quán)是積極的,選民有足夠的代幣實際投票等。然后我們從存儲中獲取提案并確保它既沒有過期也沒有已經(jīng)執(zhí)行。對已經(jīng)完成的提案進(jìn)行投票是沒有意義的。我們還需要確保這個人還沒有投票。我們可以允許改變投票權(quán),但這會讓DAO面臨一些漏洞,例如人們在最后一刻撤回投票等等。也許是未來版本的候選人?
然后我們在提案中注冊一個新的投票,更改當(dāng)前結(jié)果以便于查找分?jǐn)?shù),最后發(fā)出Voted事件。但是什么是token.increaseLockedAmount
?
這一點邏輯增加了用戶的鎖定代幣數(shù)量。該功能只能由代幣合約的所有者執(zhí)行(此時希望是DAO)并且將阻止用戶發(fā)送超過其帳戶注冊的鎖定金額的令牌數(shù)量。提案落實或執(zhí)行后,此鎖定被解除。
讓我們編寫現(xiàn)在提議刪除條目的函數(shù)。
如本系列第1部分所述 ,我們計劃了三個條目刪除功能:
1.刪除條目:通過投票確認(rèn)后,目標(biāo)條目將被刪除。投票時間:48小時。
2.緊急刪除條目[僅限所有者]:只能由所有者觸發(fā)。通過投票確認(rèn)后,目標(biāo)條目將被刪除。投票時間:24小時。
3.緊急刪除圖像[僅限所有者]:僅適用于圖像條目。只能由所有者觸發(fā)。通過投票確認(rèn)后,目標(biāo)條目將被刪除。投票時間:4小時。
單個地址條目的五個刪除導(dǎo)致黑名單。
讓我們看看我們現(xiàn)在該怎么做。首先,刪除功能:
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; }
一旦提出,建議書就會被添加到提案列表中,并記錄條目哈希所針對的條目。保存說明并添加一些默認(rèn)值,并根據(jù)提案類型計算截止日期。該提案添加了事件,并且提案總數(shù)增加了。
接下來讓我們看看如何執(zhí)行提案。為了可執(zhí)行,提案必須有足夠的票數(shù),并且必須超過其截止日期。執(zhí)行功能將接受要執(zhí)行的提議的ID。沒有簡單的方法可以讓EVM立即執(zhí)行所有待處理的提案。可能有太多人要等待執(zhí)行,并且他們會對DAO中的數(shù)據(jù)進(jìn)行大的更改,這可能會超過以太坊塊的氣體限制,從而導(dǎo)致交易失敗。構(gòu)建一個可以由具有明確規(guī)則的任何人調(diào)用的手動執(zhí)行功能要容易得多,因此社區(qū)可以關(guān)注需要執(zhí)行的提議。
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); }
我們通過其ID獲取提案,檢查它是否符合未執(zhí)行的要求和截止日期過期,然后如果提案的類型是刪除提案且投票結(jié)果是肯定的,我們使用已經(jīng)寫入的刪除功能,最后發(fā)出了我們添加的新事件(將其添加到合約的頂部)。assert
調(diào)用與require
語句具有相同的用途:斷言通常在“斷言”結(jié)果為真時使用。要求用于先決條件。在功能上它們是相同的,assert
語句的差異在它們失敗時無法接受消息參數(shù)。該功能通過為該一個提案中的所有投票解鎖代幣而結(jié)束。
我們可以使用相同的方法添加其他類型的提案,但首先,讓我們更新deleteSubmission
函數(shù)以禁止在其帳戶上有五個或更多刪除的用戶:這意味著他們一直在提交社區(qū)投票反對的內(nèi)容。讓我們更新deleteSubmission
函數(shù):
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; }
那更好。自動將五個刪除列入黑名單。但是,如果不給黑名單地址提供贖回的機會,那是不公平的。我們還需要定義黑名單功能本身。讓我們做這兩件事并將不合理的費用設(shè)置為例如0.05以太。
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 < proposalCount; i++) { if (proposals[i].executed == false && proposals[i].voters[_voter] == true) { return false; } } return true; }
請注意,列入黑名單的帳戶的令牌會被鎖定,直到他們發(fā)送不合格的費用為止。
使用我們上面寫的函數(shù)的靈感,嘗試編寫其他提議。對于劇透,請查看項目的GitHub倉庫并從那里復(fù)制最終代碼。為簡潔起見,讓我們繼續(xù)討論DAO中剩下的其他功能。
一旦達(dá)到故事的時間或章節(jié)限制,就應(yīng)該結(jié)束故事了。任何人都可以在允許提取股息的日期之后調(diào)用結(jié)束函數(shù)。首先,我們需要一個新的StoryDAO屬性和一個事件:
bool public active = true; event StoryEnded();
然后,讓我們構(gòu)建函數(shù):
function endStory() storyActive external { withdrawToOwner(); active = false; emit StoryEnded(); }
簡單:它將收集的費用發(fā)送給所有者并發(fā)出事件后停用故事。但實際上,這并沒有真正改變整個DAO中的任何內(nèi)容:其他功能對它的結(jié)束沒有反應(yīng)。那么讓我們構(gòu)建另一個修飾符:
modifier storyActive() { require(active == true); _; }
然后,我們將此修飾符添加到除withdrawToOwner
之外的所有函數(shù)中,如下所示:
function whitelistAddress(address _add) storyActive public payable {
如果DAO中遺留了任何代幣,讓我們將它們?nèi)』夭⒔庸苓@些代幣的所有權(quán),以便以后能夠在另一個故事中使用它們:
function withdrawLeftoverTokens() external onlyOwner { require(active == false); token.transfer(msg.sender, token.balanceOf(address(this))); token.transferOwnership(msg.sender); } function unlockMyTokens() external { require(active == false); require(token.getLockedAmount(msg.sender) > 0); token.decreaseLockedAmount(msg.sender, token.getLockedAmount(msg.sender)); }
unlockMyTokens
函數(shù)用于解鎖所有鎖定的代幣,以防某些鎖定代幣為特定用戶鎖定。它不應(yīng)該發(fā)生,并且應(yīng)該通過大量測試來移除此功能。
現(xiàn)在故事已經(jīng)結(jié)束,收集的費用需要分配給所有代幣持有者。我們可以重新使用我們的白名單來標(biāo)記所有取消費用的人:
function withdrawDividend() memberOnly external { require(active == false); uint256 owed = address(this).balance.div(whitelistedNumber); msg.sender.transfer(owed); whitelist[msg.sender] = false; whitelistedNumber--; }
如果這些股息未在一定時限內(nèi)撤回,業(yè)主可以抓住其余股息:
function withdrawEverythingPostDeadline() external onlyOwner { require(active == false); require(now > deadline + 14 days); owner.transfer(address(this).balance); }
留個家庭作業(yè),考慮重新使用相同部署的智能合約,清除其數(shù)據(jù),并將代幣保留在底池中并重新啟動另一章而無需重新部署是多么容易或困難。嘗試自己這樣做,并密切關(guān)注回購,以便將來更新本系列教程!還要考慮額外的激勵機制:也許賬戶中的代幣數(shù)量會影響他們從故事結(jié)束中獲得的紅利?你的想象力是極限!
鑒于我們的合約現(xiàn)在非常大,部署和/或測試它可能會超過以太坊區(qū)塊的gas限制。這是限制大型應(yīng)用程序部署在以太坊網(wǎng)絡(luò)上的原因。無論如何要部署它,在編譯期間嘗試使用代碼優(yōu)化器,方法是更改truffle.js
文件以包含用于優(yōu)化的solc設(shè)置,如下所示:
// ... module.exports = { solc: { optimizer: { enabled: true, runs: 200 } }, networks: { development: { // ...
這將在代碼中運行優(yōu)化器200次以查找在部署之前可以縮小,移除或抽象的區(qū)域,這將顯著降低部署成本。
到此,關(guān)于“以太坊構(gòu)建DApps中怎么使用定制代幣進(jìn)行投票”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。