Smart Contract開発のための新言語Vyperの環境構築・始め方

Vyperでスマートコントラクト開発をしてみましょう。
本記事はそのための環境構築をする方法について説明しています。

# Install Python3.6
Vyperを使うには、Python3.6以上が必要。
pyenvを使ってPythonをインストールする。

## Install pyenv
```shell:terminal
$ brew install pyenv
```
## .zshrcにPATHを追加

```zsh:.zshrc
export PATH="$HOME/.pyenv/shims:$PATH"
```

## Python3.6.xをインストール
```shell:terminal
$ pyenv install 3.6.7
```

## Python3.6.xを指定
```shell:terminal
$ pyenv global 3.6.7
```

## 確認
```shell:terminal
$ python -V
# => Python 3.6.7
```

# Install libralies
必要なライブラリをインストールしておく

```shell:terminal
$ brew install gmp leveldb
```

# Install virtualenv
Pythonの仮想環境を使うことを公式ドキュメントは推奨しているので、virtualenvをインストールしておく。
virtualenvを使えばプロジェクトごとにPythonのバージョンやパッケージを管理できるので、他の環境を汚さずに済む。

>It is strongly recommended to install Vyper in a virtual Python environment, so that new packages installed and dependencies built are strictly contained in your Vyper project and will not alter or affect your other development environment set-up.
> https://vyper.readthedocs.io/en/latest/installing-vyper.html


## virtualenvをインストール
```shell:terminal
$ [sudo] pip install virtualenv
```

## 確認
```shell:terminal
$ virtualenv --version
# => 16.1.0
```

## Vyper用の仮想環境を構築する
仮想環境を作成

```shell:terminal
$ virtualenv -p python3.6 --no-site-packages vyper-test
```

作成した仮想環境をactivate

```hell:terminal
$ source vyper-test/bin/activate
```

Vyperをクローンする

```hell:terminal
$ git clone https://github.com/ethereum/vyper.git
$ cd vyper
$ make
$ make test #実行完了まで結構時間がかかる...
```

これで環境構築とプロジェクトのセットアップは完了。
正しくセットアップができたかどうかは、Cloneしたディレクトリで以下を実行して確認。

```shell:terminal
$ vyper examples/crowdfund.vy
```



# Vyperについて
- Vyperの構文はPython3と同じ(ただし、Python3の全ての構文が使えるというわけではない)
- VyperはFileで構成されている
- Fileはオブジェクト指向言語におけるClassのようなもの
- 各FileはState Variables, Functions, structure-structs-typesで構成される

## Functions
- コードを実行する1つの塊(他のプログラミング言語と同様に考えればOK)
- 必ず`@public`か`@private`を指定する

### Default function
- `__defalult__`で宣言する
- functionの実行時に該当のものが見つからない時などに実行される
- Solidityのfallback functionのようなもの
- 必ず`@public`内で宣言する
- 引数や返り値は持たすことができない
- `@payable`と組み合わせた場合、Etherを送った時には必ず実行される。これは送信したEtherとユーザーアドレスの間で差分が発生しないようにするため。
- グローバル変数`msg`からは以下の3つが取得できる
  - `msg.sender`: 送り手のaddress
  - `msg.value`:送信されたETHの量
  - `msg.gas`: 提供されたgas代

## Sample Function
Vyper公式ドキュメントにあるFunctionのサンプルコード。

- bidされたETHが最高入札額より大きかったら、入札に成功し、元の最高入札者にETHが返されるコントラクト

```python:simple_open_auction.vy
# Open Auction

# Auction params
# Beneficiary receives money from the highest bidder
beneficiary: public(address)
auctionStart: public(timestamp)
auctionEnd: public(timestamp)

# Current state of auction
highestBidder: public(address)
highestBid: public(wei_value)

# Set to true at the end, disallows any change
ended: public(bool)

# Create a simple auction with `_bidding_time`
# seconds bidding time on behalf of the
# beneficiary address `_beneficiary`.
@public
def __init__(_beneficiary: address, _bidding_time: timedelta):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

# Bid on the auction with the value sent
# together with this transaction.
# The value will only be refunded if the
# auction is not won.
@public
@payable
def bid():
    # Check if bidding period is over.
    assert block.timestamp < self.auctionEnd
    # Check if bid is high enough
    assert msg.value > self.highestBid
    if not self.highestBid == 0:
        # Sends money back to the previous highest bidder
        send(self.highestBidder, self.highestBid)
    self.highestBidder = msg.sender
    self.highestBid = msg.value


# End the auction and send the highest bid
# to the beneficiary.
@public
def endAuction():
    # It is a good guideline to structure functions that interact
    # with other contracts (i.e. they call functions or send Ether)
    # into three phases:
    # 1. checking conditions
    # 2. performing actions (potentially changing conditions)
    # 3. interacting with other contracts
    # If these phases are mixed up, the other contract could call
    # back into the current contract and modify the state or cause
    # effects (Ether payout) to be performed multiple times.
    # If functions called internally include interaction with external
    # contracts, they also have to be considered interaction with
    # external contracts.

    # 1. Conditions
    # Check if auction endtime has been reached
    assert block.timestamp >= self.auctionEnd
    # Check if this function has already been called
    assert not self.ended

    # 2. Effects
    self.ended = True

    # 3. Interaction
    send(self.beneficiary, self.highestBid)
  ```

# Others

> Viperはコードの上から イベントの定義 -> 変数の型定義 -> メソッドの記述という順番を守らないとコンパイル時にエラーになります
> https://blockchain.gunosy.io/entry/compare-solidity-viper

まだまだ情報が少なく、Vyper自体もアルファ版ですが、今後に期待です。