Decentralized Autonomous Organization,簡稱DAO,以太坊中重要的概念。通常翻譯爲去中心化的自治組織。php
投票支付合約的全部費用和行動須要時間,並要求用戶始終保持活躍,知情和專一。另外一個有趣的方法是選擇一個能夠控制合約的指定帳戶,而後可以迅速作出決定。java
咱們將實施一種一般稱爲流動民主Liquid Democracy
的版本,這是一種更靈活的代議制民主。在這種民主制度下,任何選民均可以成爲潛在的表明:你只需說出你信任哪位選民就能夠爲你處理這一決定。你的投票權重被委託給他們,他們能夠將其委託給他們信任的另外一個選民,依此類推。最終結果應該是投票最多的帳戶是與最大數量的選民有信任關係的帳戶。node
代碼:python
pragma solidity >=0.4.22 <0.6.0; contract token { mapping (address => uint256) public balanceOf; } contract LiquidDemocracy { token public votingToken; bool underExecution; address public appointee; mapping (address => uint) public voterId; mapping (address => uint256) public voteWeight; uint public delegatedPercent; uint public lastWeightCalculation; uint public numberOfDelegationRounds; uint public numberOfVotes; DelegatedVote[] public delegatedVotes; string public forbiddenFunction; event NewAppointee(address newAppointee, bool changed); struct DelegatedVote { address nominee; address voter; } /** * Constructor */ constructor( address votingWeightToken, string memory forbiddenFunctionCall, uint percentLossInEachRound ) public { votingToken = token(votingWeightToken); delegatedVotes.length++; delegatedVotes[0] = DelegatedVote({nominee: address(0), voter: address(0)}); forbiddenFunction = forbiddenFunctionCall; delegatedPercent = 100 - percentLossInEachRound; if (delegatedPercent > 100) delegatedPercent = 100; } /** * Vote for an address * * Send your vote weight to another address * * @param nominatedAddress the destination address receiving the sender's vote */ function vote(address nominatedAddress) public returns (uint voteIndex) { if (voterId[msg.sender]== 0) { voterId[msg.sender] = delegatedVotes.length; numberOfVotes++; voteIndex = delegatedVotes.length++; numberOfVotes = voteIndex; } else { voteIndex = voterId[msg.sender]; } delegatedVotes[voteIndex] = DelegatedVote({nominee: nominatedAddress, voter: msg.sender}); return voteIndex; } /** * Perform Executive Action * * @param target the destination address to interact with * @param valueInWei the amount of ether to send along with the transaction * @param bytecode the data bytecode for the transaction */ function execute(address target, uint valueInWei, bytes32 bytecode) public { require(msg.sender == appointee // If caller is the current appointee, && !underExecution // if the call is being executed, && bytes4(bytecode) != bytes4(keccak256(abi.encodePacked(forbiddenFunction))) // and it's not trying to do the forbidden function && numberOfDelegationRounds >= 4); // and delegation has been calculated enough underExecution = true; (bool success, ) = target.call.value(valueInWei)(abi.encode(bytecode)); // Then execute the command. require(success); underExecution = false; } /** * Calculate Votes * * Go thruogh all the delegated vote logs and tally up each address's total rank */ function calculateVotes() public returns (address winner) { address currentWinner = appointee; uint currentMax = 0; uint weight = 0; DelegatedVote storage v = delegatedVotes[0]; if (now > lastWeightCalculation + 90 minutes) { numberOfDelegationRounds = 0; lastWeightCalculation = now; // Distribute the initial weight for (uint i=1; i< delegatedVotes.length; i++) { voteWeight[delegatedVotes[i].nominee] = 0; } for (uint i=1; i< delegatedVotes.length; i++) { voteWeight[delegatedVotes[i].voter] = votingToken.balanceOf(delegatedVotes[i].voter); } } else { numberOfDelegationRounds++; uint lossRatio = 100 * delegatedPercent ** numberOfDelegationRounds / 100 ** numberOfDelegationRounds; if (lossRatio > 0) { for (uint i=1; i< delegatedVotes.length; i++){ v = delegatedVotes[i]; if (v.nominee != v.voter && voteWeight[v.voter] > 0) { weight = voteWeight[v.voter] * lossRatio / 100; voteWeight[v.voter] -= weight; voteWeight[v.nominee] += weight; } if (numberOfDelegationRounds>3 && voteWeight[v.nominee] > currentMax) { currentWinner = v.nominee; currentMax = voteWeight[v.nominee]; } } } } if (numberOfDelegationRounds > 3) { emit NewAppointee(currentWinner, appointee == currentWinner); appointee = currentWinner; } return currentWinner; } }
首先,你須要一個代幣。若是你已按照上面的股東協會Shareholder association
教程,你可使用與以前相同的代幣,不然只需部署新代幣並在某些賬戶中分配。複製代幣地址。android
部署民主合約,並將代幣地址放在投票權重代幣上 ,將75做爲每輪中的百分比損失,並將轉讓全部權(地址)(沒有任何空格或額外字符!)做爲禁止功能 。程序員
如今部署Liquid民主並轉到其頁面。首先,任何股東都會投票決定他們信任誰表明本合約作出決定。若是你想成爲最終決策者,你能夠本身投票,或者若是你寧願沒有人表明你擔任這個角色,你能夠在零地址上投票。web
在足夠多的人投票後,你能夠執行計算投票功能,以便計算每一個人的投票權重。這個功能須要屢次運行,因此第一次運行它只會將每一個人的體重設置爲所選代幣中的餘額。在下一輪中,投票權重將轉到你投票指定的人,在下一輪它會去由你選擇的人投票的人等等。爲了防止無限循環的投票受權,每次投票都會轉發,它會失去一些權力,在percentLossInEachRound合約啓動時設定。所以,若是損失設定爲75%,則意味着你投票的人得到了100%的體重,但若是他們將投票委託給其餘人,則只有75%的體重被轉發。那我的能夠委託給別人,但他們只能得到56%的投票權,依此類推。若是比率低於100%,將會有一個有限的時刻,從新計算投票受權將再也不改變結果,但若是它是100%,則意味着投票權重將簡單地圍繞任何潛在的循環進行循環。mongodb
若是這一輪調用計算投票開始已超過一個半小時,全部權重將重置並將根據原始代幣餘額從新計算,所以若是你最近收到更多代幣,則應再次執行此功能。編程
投票表明團的全部優勢是什麼?例如,你能夠在關聯上使用它而不是代幣權重。首先,獲取股東協會的代碼,但替換描述代幣的第一行:app
contract Token { mapping (address => uint256) public balanceOf; function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); }
進入這個:
contract Token { mapping (address => uint256) public voteWeight; uint public numberOfDelegationRounds; function balanceOf(address member) public view returns (uint256 balance) { if (numberOfDelegationRounds < 3) return 0; else return this.voteWeight(member); } function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); }
在編寫合約時,你能夠描述主合約使用的多個其餘合約。有些多是已在目標合約上定義的函數和變量,如voteWeight
和numberOfDelegationRounds
。但請注意,balanceOf
是一個新功能,它在Liquid Democracy
或Association
合約上都不存在,咱們如今正在定義它,做爲一個函數,若是至少計算了三輪,它將返回voteWeight
。
使用Liquid democracy
做爲代幣地址而不是原始代幣,並像往常同樣繼續部署股東協會。就像之前同樣,用戶能夠針對這些問題建立新的提案或投票,但如今,咱們使用委託流程,不是使用代幣餘額做爲投票權。因此,若是你是一個代幣持有者,你能夠選擇一個你信任的人並指定他們,而不是讓你本身不斷地通知全部問題,而後他們能夠選擇他們信任的人:結果就是你的表明,而不是被限制在給定的任意地理位置附近,將是你社交距離的人。
此外,這意味着你能夠隨時切換投票:若是你的表明在某些問題上投票反對你的利益,你能夠在提案投票結算以前,轉換你的被任命者,或者只是選擇表明你本身處理問題並投本身投票。
代議制民主國家是選擇表明的一種很好的方式,但對於一些重要或簡單的決策,對個別提案進行投票可能太慢:這就是爲何大多數民主政府都有一個行政部門,而被任命的人有權表明國家。
在四輪表明以後,更多權重的地址將被設定爲被任命者。若是有許多委託投票,那麼可能須要再多幾輪計算投票才能在最終指定的地址中解決。
被任命者是惟一能夠調用Execute函數的地址,它能夠執行(幾乎)任何表明整個民主的函數。若是液體民主合約中存有任何以太或代幣,被任命者將被容許在任何地方移動。
若是你遵循咱們的示例並使用此流動民主做爲代幣建立了股東協會 ,那麼你應該可以以有趣的方式使用行政部門:轉到主協會地址並執行轉移全部權功能到流動民主。
傳輸完成後,將功能切換爲更改投票規則。這容許你更改一些基本的投票規則,例如投票經過所需的最低法定人數或新提案須要留在場上的時間。嘗試更改這些設置並單擊執行:當彈出確認窗口時,它將告訴你該交易沒法執行。固然,這種狀況發生,由於只有設置爲全部者的地址才能更改這些設置,合約將拒絕此交易嘗試。所以,不是鍵入密碼而是複製數據字段上的代碼並將其保存到文本文件中。單擊取消,滾動到頂部並單擊複製地址,並將其保存到文本文件。
如今轉到Liquid民族頁面並選擇執行。在目標上放置關聯合約的地址,將ether amount
保留爲0並將先前複製的代碼粘貼到字節碼數據字段中。確保你從做爲被任命者設置的賬戶執行它,而後單擊執行。
一旦交易被收回,Liquid民主將把訂單傳遞給協會,而且新的投票規則可能適用。被任命者有絕對的權力去作液體民主合約能夠執行的任何事情。你可使用相同的技術建立委派民主所擁有的Mintable代幣,而後容許被任命者填寫代幣或凍結賬戶。
爲了防止濫用權力,你能夠設置一個被禁止的人沒法作的禁止功能。若是你按照咱們的例子,禁止的功能是transferOwnership
(地址),以防止被任命者將協會的全部權轉讓給他們本身(在政治上,當總統利用他的行政權力轉移給本身之前屬於總統,這是政變或貪污)。
======================================================================
分享一些以太坊、EOS、比特幣等區塊鏈相關的交互式在線編程實戰教程:
- java以太坊開發教程,主要是針對java和android程序員進行區塊鏈以太坊開發的web3j詳解。
- python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
- php以太坊,主要是介紹使用php進行智能合約開發交互,進行帳號建立、交易、轉帳、代幣開發以及過濾器和交易等內容。
- 以太坊入門教程,主要介紹智能合約與dapp應用開發,適合入門。
- 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
- C#以太坊,主要講解如何使用C#開發基於.Net的以太坊應用,包括帳戶管理、狀態與交易、智能合約開發與交互、過濾器和交易等。
- EOS教程,本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、帳戶與錢包、發行代幣、智能合約開發與部署、使用代碼與智能合約交互等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。
- java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Java代碼中集成比特幣支持功能,例如建立地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
- php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Php代碼中集成比特幣支持功能,例如建立地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
- tendermint區塊鏈開發詳解,本課程適合但願使用tendermint進行區塊鏈開發的工程師,課程內容即包括tendermint應用開發模型中的核心概念,例如ABCI接口、默克爾樹、多版本狀態庫等,也包括代幣發行等豐富的實操代碼,是go語言工程師快速入門區塊鏈開發的最佳選擇。
匯智網原創翻譯,轉載請標明出處。這裏是原文以太坊DAO之流動民主智能合約