Skip to content

Instantly share code, notes, and snippets.

@akirattii
Last active December 23, 2016 23:14
Show Gist options
  • Save akirattii/f78684f5efedf3c980ede9c3e032fbbf to your computer and use it in GitHub Desktop.
Save akirattii/f78684f5efedf3c980ede9c3e032fbbf to your computer and use it in GitHub Desktop.
Ethereum帝国議会コントラクトβ
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