您的位置:首页 > 编程语言

congress-国会模型 智能合约 代码分享

2018-04-05 13:35 423 查看
在ethereum wallet 部署测试过的合约。
 Congress 议会 ,可以接收以太币,可以接收其它代币, 可以完成投票pragma solidity ^0.4.18;

contract owned {
address public owner;
function owned() public {
owner = msg.sender;
}

modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}

contract tokenRecipient {
event receivedEther(address sender, uint amount);
event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData);
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public {
Token t = Token(_token);
require(t.transferFrom(_from, this, _value));
emit receivedTokens(_from, _value, _token, _extraData);
}

function () payable public {
emit receivedEther(msg.sender, msg.value);
}
}

interface Token {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
}

contract Congress is owned, tokenRecipient {
// Contract Variables and events
uint public minimumQuorum;
uint public debatingPeriodInMinutes;
int public majorityMargin;
Proposal[] public proposals;
uint public numProposals;
mapping (address => uint) public memberId;
Member[] public members;
event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
event Voted(uint proposalID, bool position, address voter, string justification);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
event MembershipChanged(address member, bool isMember);
event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, int newMajorityMargin);
struct Proposal {
address recipient;
uint amount;
string description;
uint votingDeadline;
bool executed;
bool proposalPassed;
uint numberOfVotes;
int currentResult;
bytes32 proposalHash;
Vote[] votes;
mapping (address => bool) voted;
}
struct Member {
address member;
string name;
uint memberSince;
}
struct Vote {
bool inSupport;
address voter;
string justification;
}

// Modifier that allows only shareholders to vote and create new proposals
modifier onlyMembers {
require(memberId[msg.sender] != 0);
_;
}
/**
* Constructor function
*/
function Congress (
uint minimumQuorumForProposals,
uint minutesForDebate,
int marginOfVotesForMajority) payable public {
changeVotingRules(minimumQuorumForProposals, minutesForDebate, marginOfVotesForMajority);
// It’s necessary to add an empty first member
addMember(0, "");
// and let's add the founder, to save a step later
addMember(owner, 'founder');
}
/**
* Add member
*
* Make `targetMember` a member named `memberName`
*
* @param targetMember ethereum address to be added
* @param memberName public name for that member
*/
function addMember(address targetMember, string memberName) onlyOwner public {
uint id = memberId[targetMember];
if (id == 0) {
memberId[targetMember] = members.length;
id = members.length++;
}

members[id] = Member({member: targetMember, memberSince: now, name: memberName});
emit MembershipChanged(targetMember, true);
}
/**
* Remove member
*
* @notice Remove membership from `targetMember`
*
* @param targetMember ethereum address to be removed
*/
function removeMember(address targetMember) onlyOwner public {
require(memberId[targetMember] != 0);
for (uint i = memberId[targetMember]; i<members.length-1; i++){
members[i] = members[i+1];
}
delete members[members.length-1];
members.length--;
}
/**
* Change voting rules
*
* Make so that proposals need to be discussed for at least `minutesForDebate/60` hours,
* have at least `minimumQuorumForProposals` votes, and have 50% + `marginOfVotesForMajority` votes to be executed
*
* @param minimumQuorumForProposals how many members must vote on a proposal for it to be executed
* @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed
* @param marginOfVotesForMajority the proposal needs to have 50% plus this number
*/
function changeVotingRules(
uint minimumQuorumForProposals,
uint minutesForDebate,
int marginOfVotesForMajority) onlyOwner public {
minimumQuorum = minimumQuorumForProposals;
debatingPeriodInMinutes = minutesForDebate;
majorityMargin = marginOfVotesForMajority;
emit ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, majorityMargin);
}
/**
* Add Proposal
*
* Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
*
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send, in wei
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposal(
address beneficiary,
uint weiAmount,
string jobDescription,
bytes transactionBytecode) onlyMembers public returns (uint proposalID){
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
emit ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
return proposalID;
}
/**
* Add proposal in Ether
*
* Propose to send `etherAmount` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
* This is a convenience function to use if the amount to be given is in round number of ether units.
*
* @param beneficiary who to send the ether to
* @param etherAmount amount of ether to send
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposalInEther(
address beneficiary,
uint etherAmount,
string jobDescription,
bytes transactionBytecode) onlyMembers public
returns (uint proposalID) {
return newProposal(beneficiary, etherAmount * 1 ether, jobDescription, transactionBytecode);
}
/**
* Check if a proposal code matches
*
* @param proposalNumber ID number of the proposal to query
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send
* @param transactionBytecode bytecode of transaction
*/
function checkProposalCode(
uint proposalNumber,
address beneficiary,
uint weiAmount,
bytes transactionBytecode) constant public returns (bool codeChecksOut){
Proposal storage p = proposals[proposalNumber];
return p.proposalHash == keccak256(beneficiary, weiAmount, transactionBytecode);
}
/**
* Log a vote for a proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param supportsProposal either in favor or against it
* @param justificationText optional justification text
*/
function vote(
uint proposalNumber,
bool supportsProposal,
string justificationText) onlyMembers public returns (uint voteID){
Proposal storage p = proposals[proposalNumber]; // Get the proposal
require(!p.voted[msg.sender]); // If has already voted, cancel
p.voted[msg.sender] = true; // Set this voter as having voted
p.numberOfVotes++; // Increase the number of votes
if (supportsProposal) { // If they support the proposal
p.currentResult++; // Increase score
} else { // If they don't
p.currentResult--; // Decrease the score
}
// Create a log of this event
emit Voted(proposalNumber, supportsProposal, msg.sender, justificationText);
return p.numberOfVotes;
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function executeProposal(uint proposalNumber, bytes transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now > p.votingDeadline // If it is past the voting deadline
&& !p.executed // and it has not already been executed
&& p.proposalHash == keccak256(p.recipient, p.amount, transactionBytecode) // and the supplied code matches the proposal
&& p.numberOfVotes >= minimumQuorum); // and a minimum quorum has been reached...

// .
c832
..then execute result
if (p.currentResult > majorityMargin) { // Proposal passed; execute the transaction
p.executed = true; // Avoid recursive calling
require(p.recipient.call.value(p.amount)(transactionBytecode));
p.proposalPassed = true;
} else { // Proposal failed
p.proposalPassed = false;
} // Fire Events
emit ProposalTallied(proposalNumber, p.currentResult, p.numberOfVotes, p.proposalPassed);
}
}


打开以太坊钱包部署合约,输入构造函数所需参数:
Minimum quorum for proposals:提案所需最少投票数;
Minutes for debate :提案执行前的缓冲时间;
Margin of votes for majority:提案通过所需最少支持票数。



点击Deploy提交部署,等待部署通过。合约部署成功后,把合约分享给朋友们,这样DAO合约才能真正跑起来。复制合约地址和ABI,提供给自己的朋友,或者通过另一台电脑,打开钱包,点击watch contract,输入地址和ABI即可关注我们的DAO。



与DAO进行交互

在 "Read from contract"面板上的函数都是可以免费执行的,它们只是从区块链上读取信息。在这里,你可以看到当前DAO的owner,应该是合约的创建者。在“Write to contract”面板的函数会往区块链写数据,所以也需要消耗ether。选择"New Proposal",输入相关参数,可以发起一个提案。与合约交互之前,需要先添加成员。在“select function”选择器中选择“Add member”,输入地址,需要注意的是添加成员函数只有owner才能执行,所以必须确保你的账号是DAO的owner。点击Execute,等待交易被打包到下一个区块之中。合约中并没有获取所有成员的函数,但是我们可以在Members中输入一个地址以判断其是否是组织成员。同样的,我们的DAO目前还没有自己的资金,点击右上方的Transfer Ether & Tokens可以往DAO充值。

发起提案

现在我们往DAO合约发起第一个提案。在函数选择器上,选择New Proposal。"beneficiary":填写以太币接收者的地址;
"Ether Amount":填写金额,以Wei为单位;
"Job description":提案描述;
"Transaction bytecode":现在可以留空。
点击确定,输入密码,一段时间后提案将会出现在左边栏目中。

给提案投票也非常简单,选择Vote函数,输入提案编号,选择Yes or No,点击运行,即可完成投票。投票时间截止后,你可以选择“executeProposal”函数,如果提案只是发送以太币,“transactionBytecode”可以不填,点击运行。如果有提示“estimated fee consumption”,意味着由于某种原因,函数将不会执行。原因有很多,在我们的合约中,在截止时间到达前,或者你发送的bytecode与提案初始的不同,都将会看到这个提示。任何这些情况发生,合约将被终止,你也将失去你发送的以太币。如果“executeProposal”被正常执行,几秒后你将看到executed变成true,预定数量的ether将从合约转移到接收者的账户上。

拥有另一种代币

我们的DAO除了拥有以太币之外,也可以拥有代币,并且可以与任何以太坊资产进行交易。首先,我们需要先发行代币,还没有发行代币的同学,可以参考前面的文章。代币发行后,可以通过以太坊钱包转移一部分代币给我们的DAO合约。接下来,我们模拟下以太坊的行为。比如说,你要从DAO中转一部分代币给另一个账户,点击发送,但先不要输入密码,留意屏幕提示。点击 "SHOW RAW DATA" ,复制"RAW DATA"区域的数据,保存起来。然后取消交易。回到我们的DAO,用下面的参数新建一个proposal:beneficiary:输入代币合约地址;
Ether amount :留空;
Job description:随便填;
Transaction Bytecode:输入刚刚保存的数据。

几秒后你将可以看到提案细节。注意transaction bytecode并不存在,取而代之的是transaction hash。因为bytecode非常长,所以不会被保存到区块链中。调用方需要自己另外提供bytecode。但这存在一个安全漏洞:没有实际代码的情况下如何投票?提案通过后,如何阻止用户执行与提案不同的代码?为了避免这些问题,我们保存了hash值。我们提供了proposal check函数,可以根据所提供的参数检查是否与提案的一致。所以除非transaction bytecode的hash与提案保存的hash相同,否则提案不会被执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  以太坊 智能合约