Last active
December 23, 2016 23:14
-
-
Save akirattii/f78684f5efedf3c980ede9c3e032fbbf to your computer and use it in GitHub Desktop.
Ethereum帝国議会コントラクトβ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.4.7; | |
| // # テスト用パラメータ | |
| // | |
| // ## テスト・シチュエーション | |
| // - 受益者(臣民4)に利益供与(コインを送金)するかどうかを議会で決めます | |
| // | |
| // ## 登場人物のアドレス | |
| // - 初代皇帝(emperor): accounts[0] 0x4a1c11eaec40197beb6e8607ee61953e7d6d8731 | |
| // - 臣民1(subject1): accounts[1] 0x5855a19b64e1068a1edc39bb817647e16a1c57e7 | |
| // - 臣民2(subject2): accounts[2] 0x585542d64e07e856c3233042bc2d20a6711bbd75 | |
| // - 臣民3(subject3): accounts[3] 0xca100510bd8c2b9689e8d35751f8c1c83bee27cc | |
| // - 臣民4&受益者(subject4): accounts[4] 0xc49f4225795c06857eab6fcdb695faa2d2cd39f9 | |
| // | |
| // ## 議会 | |
| // - 初代議長: 皇帝 | |
| // - 討議時間: 10分 | |
| // - マジョリティ得票数との差数: 1票 (賛成票が1票上まれば可決) | |
| // | |
| // ## コイン | |
| // - 最小単位: 1厘(シンボル:"RIN") | |
| // - 初期鋳造数量: 10000 | |
| // =================================================================== | |
| // | |
| // 帝国を表すコントラクト | |
| // | |
| // =================================================================== | |
| contract Empire { | |
| // --------------------------------------------------- | |
| // public変数 | |
| // --------------------------------------------------- | |
| address public emperor; | |
| // --------------------------------------------------- | |
| // コンストラクタ | |
| // --------------------------------------------------- | |
| // Note: コントラクトの作成者が初代皇帝 | |
| function Empire() { | |
| emperor = msg.sender; | |
| } | |
| // --------------------------------------------------- | |
| // modifier | |
| // --------------------------------------------------- | |
| // 皇帝だけが実行できる関数を作るためのmodifier | |
| modifier onlyEmperor { | |
| if (msg.sender != emperor) throw; | |
| _; | |
| } | |
| // --------------------------------------------------- | |
| // 関数 | |
| // --------------------------------------------------- | |
| // 皇位の継承(皇帝のみが実行可能) | |
| function imperialSuccession(address newEmperor) onlyEmperor { | |
| emperor = newEmperor; | |
| } | |
| } | |
| // =================================================================== | |
| // | |
| // 帝国議会を表すコントラクト | |
| // | |
| // =================================================================== | |
| contract ImperialDiet is Empire { | |
| // --------------------------------------------------- | |
| // public変数 | |
| // --------------------------------------------------- | |
| // -- 議会関係 -- | |
| uint public minimumQuorum; // 定足数 | |
| uint public debatingPeriodInMinutes; // 討議時間(分) | |
| int public majorityMargin; // マジョリティ得票数との差数 | |
| Proposal[] public proposals; // 議案一覧 | |
| uint public numProposals; // 議案数 | |
| mapping (address => uint) public memberId; // 帝国民ID一覧 | |
| Member[] public members; // 帝国民一覧 | |
| // -- 政府発行コイン関係 -- | |
| string public coinSymbol; // コインシンボル | |
| uint256 public coinTotalSupply; // コイン総量 | |
| mapping (address => uint256) public coinBalanceOf; // アドレス毎のコイン残高 | |
| // --------------------------------------------------- | |
| // イベント | |
| // --------------------------------------------------- | |
| // 議案追加イベント | |
| 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 minimumQuorum, uint debatingPeriodInMinutes, int majorityMargin); | |
| // コイン送金イベント | |
| event CoinTransfer(address from, address to, uint256 value); | |
| // デバッグログイベント | |
| event Log(string calledFunc, address sender, string message); | |
| // --------------------------------------------------- | |
| // 構造体 | |
| // --------------------------------------------------- | |
| // 議案 | |
| struct Proposal { | |
| address recipient; // 受取人 | |
| uint amount; // コイン数量 | |
| string description; // 記述 | |
| uint votingDeadline; // 投票期限 | |
| bool executed; // 実行済みフラグ | |
| bool proposalPassed; // 議案通過フラグ | |
| uint numberOfVotes; // 総投票数 | |
| int currentResult; // 現在の集票結果 | |
| bytes32 proposalHash; // 議案ハッシュ(改ざん検証用) | |
| mapping (address => bool) voted; // 帝国民に紐づく投票の一覧 | |
| } | |
| // 帝国民 | |
| struct Member { | |
| address member; // 帝国民のアドレス | |
| string name; // 帝国民の名前 | |
| uint memberSince; // 帝国民になった日 | |
| } | |
| // --------------------------------------------------- | |
| // Modifier | |
| // --------------------------------------------------- | |
| // トークン保有者にのみ実行を許可するためのmodifier | |
| modifier onlyMembers { | |
| if (memberId[msg.sender] == 0) throw; | |
| _; | |
| } | |
| // --------------------------------------------------- | |
| // コンストラクタ | |
| // --------------------------------------------------- | |
| // 議会コントラクトのコンストラクタ | |
| // Note: 初回セットアップ時の一回のみ実行されます | |
| function ImperialDiet( | |
| uint _minimumQuorumForProposals, // 議案の定足数 | |
| uint _minutesForDebate, // 討議時間(分) | |
| int _marginOfVotesForMajority, // マジョリティ得票数との差数 | |
| address _congressLeader, // 議長 (この議会のオーナー) | |
| uint256 _coinTotalSupply, // コイン総量 | |
| string _coinSymbol // コインシンボル | |
| ) payable { | |
| // まずは、、、 | |
| // 最初に投票ルールを策定し、 | |
| changeVotingRules( | |
| _minimumQuorumForProposals, | |
| _minutesForDebate, | |
| _marginOfVotesForMajority | |
| ); | |
| // まずは皇帝を議長として指定、 | |
| if (_congressLeader != 0) emperor = _congressLeader; | |
| addMember(0, ''); // 初期化 | |
| // そして、ひとまず議長を 'founder' として帝国民登録 | |
| addMember(emperor, 'founder'); | |
| // 政府発行コインのシンボルを設定して | |
| coinSymbol = _coinSymbol; | |
| // 政府発行コインの総量をセットして | |
| coinTotalSupply = _coinTotalSupply; | |
| // 政府発行コインをまずは全額皇帝に持たせる | |
| coinBalanceOf[msg.sender] = _coinTotalSupply; | |
| } | |
| // --------------------------------------------------- | |
| // 関数 | |
| // --------------------------------------------------- | |
| // 帝国民を追加する関数 | |
| // Note: 皇帝だけが実行できます | |
| function addMember(address targetMember, string memberName) onlyEmperor { | |
| uint id; | |
| // 帝国民一覧と帝国民ID一覧を更新 | |
| if (memberId[targetMember] == 0) { | |
| memberId[targetMember] = members.length; | |
| id = members.length++; | |
| members[id] = Member({member: targetMember, memberSince: now, name: memberName}); | |
| } else { | |
| id = memberId[targetMember]; | |
| Member m = members[id]; | |
| } | |
| // 帝国民情報変更イベントを発火 | |
| MembershipChanged(targetMember, true); | |
| } | |
| // 帝国民を削除する関数 | |
| // Note: 皇帝だけが実行できます | |
| function removeMember(address targetMember) onlyEmperor { | |
| if (memberId[targetMember] == 0) throw; | |
| // 帝国民一覧と帝国民ID一覧から削除 | |
| for (uint i = memberId[targetMember]; i < members.length - 1; i++) { | |
| members[i] = members[i + 1]; | |
| } | |
| delete members[members.length - 1]; | |
| members.length--; | |
| } | |
| // 投票ルールを変える関数 | |
| // Note: 皇帝だけが実行できます | |
| function changeVotingRules( | |
| uint minimumQuorumForProposals, // 議案の定足数 | |
| uint minutesForDebate, // 討議時間(分) | |
| int marginOfVotesForMajority // マジョリティ得票数との差数 | |
| ) onlyEmperor { | |
| minimumQuorum = minimumQuorumForProposals; | |
| debatingPeriodInMinutes = minutesForDebate; | |
| majorityMargin = marginOfVotesForMajority; | |
| // ルール変更イベントの通知 | |
| ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, majorityMargin); | |
| } | |
| // 新たな議案を作る関数 | |
| // Note: 帝国民だけが実行できます | |
| function newProposal( | |
| address beneficiary, // 受益者 | |
| uint coinAmount, // 受益者に与えるコイン数量 | |
| string JobDescription, // 職務記述 | |
| bytes transactionBytecode // トランザクションのバイトコード | |
| ) | |
| onlyMembers // 実行できるのは帝国民だけ | |
| returns (uint proposalID) // 戻り値は議案ID | |
| { | |
| proposalID = proposals.length++; | |
| Proposal p = proposals[proposalID]; | |
| p.recipient = beneficiary; | |
| p.amount = coinAmount; | |
| p.description = JobDescription; | |
| p.proposalHash = sha3(beneficiary, coinAmount, transactionBytecode); | |
| p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes; | |
| p.executed = false; | |
| p.proposalPassed = false; | |
| p.numberOfVotes = 0; | |
| // 議案追加イベント発火 | |
| ProposalAdded(proposalID, beneficiary, coinAmount, JobDescription); | |
| numProposals = proposalID + 1; // 議案数をインクリメント | |
| } | |
| // 議案の改ざんをチェックする関数 | |
| function checkProposalCode( | |
| uint proposalNumber, // 議案番号 | |
| address beneficiary, // 受益者 | |
| uint coinAmount, // コイン数量 | |
| bytes transactionBytecode // トランザクションのバイトコード | |
| ) | |
| constant | |
| returns (bool codeChecksOut) | |
| { | |
| Proposal p = proposals[proposalNumber]; | |
| return p.proposalHash == sha3(beneficiary, coinAmount, transactionBytecode); | |
| } | |
| // 投票関数 | |
| // Note: 帝国民だけが実行できます | |
| function vote( | |
| uint proposalNumber, // 議案番号 | |
| bool supportsProposal, // 議案の賛否 | |
| string justificationText // 理由 | |
| ) | |
| onlyMembers // 実行できるのは帝国民だけ | |
| returns (uint voteID) // 戻り値は投票ID | |
| { | |
| Proposal p = proposals[proposalNumber]; // 議案番号から議案を取得 | |
| if (p.voted[msg.sender] == true) throw; // 投票者が既に投票済みならスローしてキャンセル | |
| p.voted[msg.sender] = true; // 投票済みフラグを立てる | |
| p.numberOfVotes++; // 総投票数をインクリメント | |
| if (supportsProposal) { | |
| // 議案に賛成(賛成票を1票増やす) | |
| p.currentResult++; | |
| } else { | |
| // 議案に反対(賛成票を1票減らす) | |
| p.currentResult--; | |
| } | |
| // 投票イベントを発火 | |
| Voted(proposalNumber, supportsProposal, msg.sender, justificationText); | |
| } | |
| // 議案を実行する関数 | |
| function executeProposal( | |
| uint proposalNumber, // 議案番号 | |
| bytes transactionBytecode // トランザクションのバイトコード | |
| ) | |
| returns (int result) // 戻り値は結果ID | |
| { | |
| Proposal p = proposals[proposalNumber]; // 議案番号から議案を取得 | |
| // 議案を実行してもよいかどうかのチェックシート: | |
| // | |
| // - 既に投票期限は過ぎていますか? | |
| // - 議案が既に実行されていませんか?(二重実行を回避) | |
| // - 議案が改ざんされていませんか? | |
| // - 定足数を満たしていますか? | |
| // | |
| // 上記のうちどれかが1つでも欠けると議案はスローされます | |
| if (now < p.votingDeadline | |
| || p.executed | |
| || p.proposalHash != sha3(p.recipient, p.amount, transactionBytecode) | |
| || p.numberOfVotes < minimumQuorum) | |
| throw; | |
| if (p.currentResult > majorityMargin) { | |
| // | |
| // 賛成票が既定のマジョリティ投票数の差数を超えていたら: | |
| // | |
| // 二重実行を避けるために実行済みフラグを立てる | |
| p.executed = true; | |
| // 受益者にコインを送金 | |
| if (!transferFrom(emperor, p.recipient, p.amount)) { | |
| throw; // 送金失敗だったらスロー | |
| } | |
| // // 受益者にEtherを送金 | |
| // if (!p.recipient.call.value(p.amount * 1 ether)(transactionBytecode)) { | |
| // throw; // 送金失敗だったらスロー | |
| // } | |
| p.proposalPassed = true; // 議案通過フラグを立てる | |
| } else { | |
| p.proposalPassed = false; // 議案通過フラグを下ろす | |
| } | |
| // 票集計完了イベントを発火 | |
| ProposalTallied(proposalNumber, p.currentResult, p.numberOfVotes, p.proposalPassed); | |
| } | |
| // コイン送金関数 | |
| function transferFrom( | |
| address _from, // 送金元 | |
| address _to, // 送金先 | |
| uint256 _value // 送金額 | |
| ) returns (bool success) { | |
| // 送金者が十分な額を持っているかチェック | |
| if (coinBalanceOf[_from] < _value) throw; | |
| // 送金先の残高がオーバーフローしないかチェック | |
| if (coinBalanceOf[_to] + _value < coinBalanceOf[_to]) throw; | |
| // コイン送金 | |
| coinBalanceOf[_from] -= _value; | |
| coinBalanceOf[_to] += _value; | |
| // コイン送金イベントを発火 | |
| CoinTransfer(_from, _to, _value); | |
| return true; | |
| } | |
| // コインを鋳造する関数 | |
| // Note: 皇帝だけが実行できます | |
| function mintCoin( | |
| address target, // 割当先 | |
| uint256 mintedAmount // 鋳造数量 | |
| ) onlyEmperor { | |
| coinBalanceOf[target] += mintedAmount; | |
| coinTotalSupply += mintedAmount; | |
| // コイン送金イベントを発火: 0x -> emperor -> target | |
| CoinTransfer(0, emperor, mintedAmount); | |
| CoinTransfer(emperor, target, mintedAmount); | |
| } | |
| // --------------------------------------------------- | |
| // 無名関数 | |
| // Note: 誰かがEtherを送金しようとする度に実行されます | |
| // --------------------------------------------------- | |
| function() { | |
| throw; // アクシデントによる送金を防止 | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment