前回はSolidityの使い方についてご説明しました。今回はSolidityを用いてオプション取引を実装してみましょう。
##コントラクト概要
今回はコール・オプションを実装します。コール・オプションとはある資産を買う権利のことです。(ちなみにある資産を売る権利をプット・オプションといいます)。
コール・オプションのカラムは以下のようにします。
key | value |
---|---|
資産 | ビットコイン |
数量 | 1 |
権利行使価格 | ¥50,000 |
プレミアム | ¥5,000 |
期日 | 1463127335 |
売り手 | 0xfffe72483eb0bc804295af2416d2aeb4fa15a8bc |
買い手 | 0x0e7b3774402f2f19a05e7a279238a4a1fe5e2bc0 |
※1463127335は**2016/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を用いたオプション取引の実装方法をご説明しました。次回はスワップ取引の実装方法をご紹介致します。