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

前回はSolidityの使い方について説明しました。

sendeetech.hatenablog.com

今回はSolidityを用いてオプション取引を実装してみましょう。

コントラクト概要

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

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

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

14631273352016/05/13 8:15am(UTC)UNIX TimeStampです

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

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を用いたオプション取引の実装方法を説明しました。
次回はスワップ取引の実装方法をご紹介致します。

sendeetech.hatenablog.com