15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Solidityによるコントラクトの作成(1) - 基礎

Last updated at Posted at 2016-05-11

今回はSolidityを用いたコントラクトの作り方について説明致します。

開発環境
OS : OSX 10.11.4

Ethereumインストール

Ethereumをインストールしていない方は、インストールしてください。
Consoleで以下のコマンドを叩けばインストールされます。

bash <(curl https://install-geth.ethereum.org -L)
```
その他のインストール方法については[こちら](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)を参考にしてください。

## Ethereum立ち上げ
続いてEthereumをを立ち上げましょう。今回はテスト用に使うため、Private_netを立ち上げます。

```
geth --networkid "11"  --datadir "path_to_directory" --genesis "path_to_genesisjson" console
```

`--networkid`:networkIDを指定します。1,2,3以外の数字を使いましょう。
`--genesis` :genesis blockを指定します。
`--datadir` :databaseのあるディレクトリを指定します。
`console`  :consoleを開くために必要です。

[geth command line options](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)

## コントラクト作成
早速コントラクトを記述してみましょう。言語はSolidityを使います。
(事前にsolidityコンパイラ(solc)がインストールされているか確認してください。されてない場合は[こちらの記事](http://book.ethereum-jp.net/first_use/contract.html)に沿ってインストールしてください。)

エディタで次のようなコントラクトを記述しましょう。これはEthereum上に独自のコインを作るためのコントラクトです。

```token.sol
contract token { 
    mapping (address => uint) public coinBalanceOf;
    event CoinTransfer(address sender, address receiver, uint amount);

  /* Contract初期化のための関数。contract名と同じにする */
  function token(uint supply) {
        coinBalanceOf[msg.sender] = supply;
    }

  /* コインを送るための関数 */
    function sendCoin(address receiver, uint amount) returns(bool sufficient) {
        if (coinBalanceOf[msg.sender] < amount) return false;
        coinBalanceOf[msg.sender] -= amount;
        coinBalanceOf[receiver] += amount;
        CoinTransfer(msg.sender, receiver, amount);
        return true;
    }
}
```

このコントラクトから改行を削除します。テキストから改行を削除する方法については[こちらの記事](http://linux.just4fun.biz/%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E6%94%B9%E8%A1%8C%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B.html)を参考にしてください。

```token_one_line.sol
contract token {    mapping (address => uint) public coinBalanceOf;    event CoinTransfer(address sender, address receiver, uint amount);  /* Contract初期化のための関数。contract名と同じにする */  function token(uint supply) {        coinBalanceOf[msg.sender] = supply;    }  /* コインを送るための関数 */    function sendCoin(address receiver, uint amount) returns(bool sufficient) {        if (coinBalanceOf[msg.sender] < amount) return false;        coinBalanceOf[msg.sender] -= amount;        coinBalanceOf[receiver] += amount;        CoinTransfer(msg.sender, receiver, amount);        return true;    }}
```

### コンパイル
続いて、`solc`を用いてコントラクトをコンパイルします。

```
> var source = "contract token {    mapping (address => uint) public coinBalanceOf;    event CoinTransfer(address sender, address receiver, uint amount);  /* Contract初期化のための関数。contract名と同じにする */  function token(uint supply) {        coinBalanceOf[msg.sender] = supply;    }  /* コインを送るための関数 */    function sendCoin(address receiver, uint amount) returns(bool sufficient) {        if (coinBalanceOf[msg.sender] < amount) return false;        coinBalanceOf[msg.sender] -= amount;        coinBalanceOf[receiver] += amount;        CoinTransfer(msg.sender, receiver, amount);        return true;    }}"
> var compiledSource = eth.compile.solidity(source)
```

これでコンパイルは完了しました。続いてコンパイルしたコードをEthereumのネットワークに送信します。

```
> var abiDefinition = compiledSource.token.info.abiDefinition
> var compiledContract = eth.contract(abiDefinition)
> var supply = 10000
> var contract = compiledContract.new(supply, {from:eth.accounts[0], data: compiledSource.token.code, gas:1000000})
```

これでネットワークへの送信は完了しました。しかしまだマイニングは行われていないので、このコントラクトは承認されていません。そのためaddressもまだ未定です。

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

マイニングが完了すると以下のようにaddressが付与されます。

```
> contract
{
  address: "0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6",
  transactionHash: "0x09b7b27e8d948b601ef1dd0548c7d33604c2fc7b8ee31d7d8e637f66da302a69",
  CoinTransfer: function(),
  allEvents: function(),
  coinBalanceOf: function(),
  sendCoin: function()
}
```

### コントラクトのメソッドを用いる

コントラクトで定義されているメソッドを呼び出してみましょう。
以下のsendCoinメソッドは引数を2つとります。1つ目は受取主、2つ目は送金額です。

```
> contract.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]})
I0511 22:09:00.939817    8397 xeth.go:1028] Tx(0xcd1003befe323aa1cdaee4e81e032b07cfe70fffc33400f46d033dc86cf4c4a1) to: 0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6
"0xcd1003befe323aa1cdaee4e81e032b07cfe70fffc33400f46d033dc86cf4c4a1"
```

メソッドがネットワークに送信されました。しかしまだマイニングされていないので、eth.accounts[0]の残高は10,000、eth.accounts[1]の残高は0のままです。

```
> contract.coinBalanceOf(eth.accounts[0])
10000
> contract.coinBalanceOf(eth.accounts[1])
0
```

マイニングを行います。すると残高が以下のように変化します。

```
> contract.coinBalanceOf(eth.accounts[0])
9000
> contract.coinBalanceOf(eth.accounts[1])
1000
```

以上がコントラクト内のメソッドの呼び出し方です。

### 外部からコントラクトにアクセスする

第三者がコントラクトにアクセスするには`AbiDefinition`と`address`が必要です。今回の場合は以下になります。

```
> abiDefinition 
[{
    constant: false,
    inputs: [{
        name: "receiver",
        type: "address"
    }, {
        name: "amount",
        type: "uint256"
    }],
    name: "sendCoin",
    outputs: [{
        name: "sufficient",
        type: "bool"
    }],
    type: "function"
}, {
    constant: true,
    inputs: [{
        name: "",
        type: "address"
    }],
    name: "coinBalanceOf",
    outputs: [{
        name: "",
        type: "uint256"
    }],
    type: "function"
}, {
    inputs: [{
        name: "supply",
        type: "uint256"
    }],
    type: "constructor"
}, {
    anonymous: false,
    inputs: [{
        indexed: false,
        name: "sender",
        type: "address"
    }, {
        indexed: false,
        name: "receiver",
        type: "address"
    }, {
        indexed: false,
        name: "amount",
        type: "uint256"
    }],
    name: "CoinTransfer",
    type: "event"
}]
```

```
> contract.address
"0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6"
```

上記のデータを用いて、コントラクトにアクセスする変数を作成します。


```
> var theContract = eth.contract(abiDefinition).at(contract.address)
> theContract
{
  address: "0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6",
  CoinTransfer: function(),
  allEvents: function(),
  coinBalanceOf: function(),
  sendCoin: function()
}
```

これで第三者がコントラクトにアクセス出来るようになりました。


### まとめ
以上Solidityを使ったコントラクトの作成方法でした。次回はSolidityを用いたデリバティブの実装方法についてご説明致します。


### 参考記事
https://ethereum.gitbooks.io/frontier-guide/content/ether_transfer.html
http://book.ethereum-jp.net/first_use/contract.html
https://solidity.readthedocs.io/en/latest/index.html
http://linux.just4fun.biz/%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E6%94%B9%E8%A1%8C%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B.html
15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?