Solidityによるコントラクトの作成(2) - オプション取引

[前回](http://qiita.com/toshikase/items/28725215f7ad678b4b68)はSolidityの使い方についてご説明しました。今回はSolidityを用いてオプション取引を実装してみましょう。

##コントラクト概要
今回はコール・オプションを実装します。コール・オプションとはある資産を買う権利のことです。(ちなみにある資産を売る権利をプット・オプションといいます)。

コール・オプションのカラムは以下のようにします。

| key | value | 
|:----------|:-----------|
| 資産 | ビットコイン |
| 数量 | 1 | 
| 権利行使価格 | ¥50,000 |
| プレミアム | ¥5,000 | 
| 期日 |  1463127335 |
| 売り手 |  0xfffe72483eb0bc804295af2416d2aeb4fa15a8bc | 
| 買い手 | 0x0e7b3774402f2f19a05e7a279238a4a1fe5e2bc0 |  

※**1463127335**は**2016/05/13 8:15am(UTC)**の[UNIX TimeStamp](http://www.unixtimestamp.com/)です

以下が完成形のコードです

```call_option.sol
contract CallOption{
    address public buyer;
    address public seller;
    uint public btc_amount;
    uint public btc_price;
    uint public premium;
    uint public exercise_date;
    mapping (address => uint) public balanceOfJPY;
    mapping (address => uint) public balanceOfBTC;
    function CallOption(
      address _seller,
      uint _seller_jpy,
      uint _seller_btc,
      uint _btc_price,
      uint _btc_amount,
      uint _premium,
      uint _exercise_date
      ){
      seller = _seller;
      balanceOfJPY[seller] = _seller_jpy;
      balanceOfBTC[seller] = _seller_btc;
      btc_price = _btc_price;
      btc_amount = _btc_amount;
      premium = _premium;
      exercise_date = _exercise_date;
    }
    function Respond (address _buyer, uint _buyer_jpy) {
      buyer = _buyer;
      balanceOfJPY[buyer] = _buyer_jpy;
      if (balanceOfJPY[buyer] < premium + btc_amount * btc_price) throw;
      balanceOfJPY[buyer] -= premium;
      balanceOfJPY[seller] += premium;
    }
    function Expire (uint _current_btc_price, uint _current_time){
      if (_current_time < exercise_date) throw;
      if (_current_btc_price < btc_price) throw;
      balanceOfJPY[buyer] -= btc_price * btc_amount;
      balanceOfJPY[seller] += btc_price * btc_amount;
      balanceOfBTC[buyer] += btc_amount;
      balanceOfBTC[seller] -= btc_amount;
    }
    function () {
      throw;
    }
}
```

- CallOption：初期化(今回は、オプションの発行主体は常に売り手とします。)
- Respond：買い手の登録
- Expire：オプション実行

##コントラクト登録

まずコードをコンパイルします。

```
> var source = "contract CallOption{    address public buyer;    address public seller;    uint public btc_amount;    uint public btc_price;    uint public premium;    uint public exercise_date;    mapping (address => uint) public balanceOfJPY;    mapping (address => uint) public balanceOfBTC;    function CallOption(      address _seller,      uint _seller_jpy,      uint _seller_btc,      uint _btc_price,      uint _btc_amount,      uint _premium,      uint _exercise_date      ){      seller = _seller;      balanceOfJPY[seller] = _seller_jpy;      balanceOfBTC[seller] = _seller_btc;      btc_price = _btc_price;      btc_amount = _btc_amount;      premium = _premium;      exercise_date = _exercise_date;    }    function Respond (address _buyer, uint _buyer_jpy) {      buyer = _buyer;      balanceOfJPY[buyer] = _buyer_jpy;      if (balanceOfJPY[buyer] < premium + btc_amount * btc_price) throw;      balanceOfJPY[buyer] -= premium;      balanceOfJPY[seller] += premium;    }    function Expire (uint _current_btc_price, uint _current_time){      if (_current_time < exercise_date) throw;      if (_current_btc_price < btc_price) throw;      balanceOfJPY[buyer] -= btc_price * btc_amount;      balanceOfJPY[seller] += btc_price * btc_amount;      balanceOfBTC[buyer] += btc_amount;      balanceOfBTC[seller] -= btc_amount;    }    function () {      throw;    }}"
> var compiledSource = eth.compile.solidity(source)
```

続いて、コントラクトをEthereumのネットワークに送信します。

```
> var abiDefinition = compiledSource.CallOption.info.abiDefinition
> var compiledContract = eth.contract(abiDefinition)
> var seller = "0xfffe72483eb0bc804295af2416d2aeb4fa15a8bc"
> var buyer = "0x0e7b3774402f2f19a05e7a279238a4a1fe5e2bc0"
> var contract = compiledContract.new(seller, 100000, 1,  50000, 1, 1463127335, {from: seller, data: compiledSource.CallOption.code, gas:1000000})
```

以下のようにコントラクトが送信されました。
しかしまだマイニングされていないので、アドレスは割り当てられていません。

```
> contract
{
  address: undefined,
  transactionHash: "0xf194ae6298b85b7fa6b0a9b75d115181ffb44ef546e4da9bcd970b943b01fa02"
}
```

マイニングが完了すると以下のようになります。アドレスが付与されるているのがわかります。

```
> contract
{
  address: "0x0bc2c62ecc340e0a4606d087f2d9d9afe0ef16d6",
  transactionHash: "0xf194ae6298b85b7fa6b0a9b75d115181ffb44ef546e4da9bcd970b943b01fa02",
  Expire: function(),
  Respond: function(),
  allEvents: function(),
  balanceOfBTC: function(),
  balanceOfJPY: function(),
  btc_amount: function(),
  btc_price: function(),
  buyer: function(),
  exercise_date: function(),
  premium: function(),
  seller: function()
}

```

##Respondメソッド
初期化が完了しました。続いてRespondメソッドを実行しましょう。
以下がコードです。第一引数は買い手のアドレス、第二引数は買い手のJPY残高を表しています。

```
 function Respond (address _buyer, uint _buyer_jpy) {
      buyer = _buyer;
      balanceOfJPY[buyer] = _buyer_jpy;
      if (balanceOfJPY[buyer] < premium + btc_amount * btc_price) throw;
      balanceOfJPY[buyer] -= premium;
      balanceOfJPY[seller] += premium;
 }
```

以下の条件文は、もしも買い手のJPY残高が (ビットコインの購入費+プレミアム) より少ない場合は、このメソッドは無効にするものです。

```
if (balanceOfJPY[buyer] < premium + btc_amount * btc_price) throw;
```

メソッドを呼び出しましょう。

```
> contract.Respond.sendTransaction(buyer, 100000, {from: buyer, gas:1000000})
```

まだマイニングが完了していないので、売りてと買い手のJPY残高は変化していません。

```
> contract.balanceOfJPY(seller)
100000
> contract.balanceOfJPY(buyer)
0
```

マイニング完了後は以下のように残高が変化します。プレミアム分だけ売り手の残高が増えているのがわかります。

```
> contract.balanceOfJPY(seller)
105000
> contract.balanceOfJPY(buyer)
95000
```

##Expireメソッド呼び出し
最後にExpireメソッドを実行しましょう。これは期日を過ぎたら、契約内容に沿って取引を実効するメソッドです。

```
  function Expire (uint _current_btc_price, uint _current_time){
      if (_current_time < exercise_date) throw; 
      if (_current_btc_price < btc_price) throw;
      balanceOfJPY[buyer] -= btc_price * btc_amount;
      balanceOfJPY[seller] += btc_price * btc_amount;
      balanceOfBTC[buyer] += btc_amount;
      balanceOfBTC[seller] -= btc_amount;
    }
```

期日に達してない場合は無効とする条件文です。

```
if (_current_time < exercise_date) throw;
```

現在のBTC価格が、権利行使価格より安い場合は無効とする条件文です。

```
if (_current_btc_price < btc_price) throw;
```

メソッドを呼び出します。

```
contract.Expire.sendTransaction(55000, 1463127340, {from:seller, gas:1000000}
```

BTC価格は¥55000(>¥50000)、現在時刻は1463127340(>1463127335)であるため、契約は実行されるはずです。

マイニング前

```
> contract.balanceOfBTC(seller)
1
> contract.balanceOfBTC(buyer)
0
> contract.balanceOfJPY(seller)
105000
> contract.balanceOfJPY(buyer)
95000

```

マイニング後

```
> contract.balanceOfBTC(seller)
0
> contract.balanceOfBTC(buyer)
1
> contract.balanceOfJPY(seller)
155000
> contract.balanceOfJPY(buyer)
45000
```

契約条件に沿って、売り手と買い手のJPY残高とBTC残高が変化しているのが確認出来ました。


##まとめ
今回はSolidityを用いたオプション取引の実装方法をご説明しました。次回はスワップ取引の実装方法をご紹介致します。