Ethereum(10) - クラウドファンディング用のスマートコントラクト

今回は、クラウドファンディング用のスマートコントラクトを作成します。

クラウドファンディングの仕様

スマートコントラクトの仕様は次の通りです。

  • etherで資金を募る。
  • 投資家はスマートコントラクトに対してetherを伴う形でトランザクションを発生させて投資する。
  • スマートコントラクトはキャンペーンの締め切りと目標額を設定する。
  • 締め切りを迎えた時点で目標額に達していたら、オーナーに集めたetherを送金する。
  • 締め切りを迎えた時点で目標額に満たなければ、各投資家に返金する。

クラウドファンディングのソース

クラウドファンディングのソースは以下のようになります。

[ソース]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
pragma solidity ^0.4.11;
contract CrowdFunding {
// 投資家
struct Investor {
address addr; // アドレス
uint amount; // 投資額
}

address public owner; // コントラクトのオーナー
uint public numInvestors; // 投資家の数
uint public deadline; // 締め切り(UnixTime)
string public status; // キャンペーンのステータス
bool public ended; // キャンペーンが終了しているかどうか
uint public goalAmount; // 目標額
uint public totalAmount; // 投資の総額
mapping (uint => Investor) public investors; // 投資家管理用のマップ

modifier onlyOwner () {
require(msg.sender == owner);
_;
}

/// コンストラクタ
function CrowdFunding(uint _duration, uint _goalAmount) {
owner = msg.sender;

// 締め切りを設定(UnixTime)
deadline = now + _duration;

goalAmount = _goalAmount;
status = "Funding";
ended = false;

numInvestors = 0;
totalAmount = 0;
}

/// 投資する際に呼び出される関数
function fund() payable {
// キャンペーンが終わっていれば処理を中断
require(!ended);

Investor inv = investors[numInvestors++];
inv.addr = msg.sender;
inv.amount = msg.value;
totalAmount += inv.amount;
}

/// 目標額に達したかどうかを確認する
/// キャンペーンの成功/失敗に応じたetherの返金をする
function checkGoalReached () public onlyOwner {
// キャンペーンが終わっていれば処理を中断
require(!ended);

// 締め切り前の場合は処理を中断
require(now >= deadline);

if(totalAmount >= goalAmount) { // キャンペーンに成功
status = "Campaign Succeeded";
ended = true;
// オーナーにコントラクト内のすべてのetherを送金する
if(!owner.send(this.balance)) {
throw;
}
} else { // キャンペーンに失敗
uint i = 0;
status = "Campaign Failed";
ended = true;

// 投資家毎にetherを返金する
while(i <= numInvestors) {
if(!investors[i].addr.send(investors[i].amount)) {
throw;
}
i++;
}
}
}

/// コントラクトを破棄
function kill() public onlyOwner {
selfdestruct(owner);
}
}
  • struct(4-7行目)
    構造体です。
    複数の変数をまとめて宣言することができます。
  • mapping(16行目)
    キーとバリューをとるデータ構造を表現します。
    キーには投資額(uint型)、バリューには投資家(Investor型)を宣言しています。
  • コンストラクタ(24-36行目)
    締め切り(deadline)、目標額(goalAmount)などの初期値を設定します。
  • fund関数(39-47行目)
    投資するときに呼び出される関数で、etherの送金を伴う形で呼び出されます。
    キャンペーンが終了していなければ、Investorを生成してマップに登録し、投資総額を更新します。
    etherを受け取る関数のためpayableを付与しています。
  • checkGoalReached(51-78行目)
    キャンペーン終了時にオーナーによってのみ呼び出される関数です。
    キャンペーンが終了し、目標額に達している場合はオーナーに集められた投資額が送金されます。
    目標額に満たなかった場合は、投資家にetherが返金されます。

デプロイ

Mist Walletでスマートコントラクトをデプロイします。

デプロイの手順は下記の記事をご参照ください。

デプロイの参考記事 - Ethereum(8) - スマートコントラクト①


次回は、キャンペーンに成功するケースで処理を実行してみます。