DYDX(DeFi)を使ってみる。

# DYDXを始める

- [DYDXを始める](#dydxを始める)
- [DYDXとは](#dydxとは)
- [誰向け？](#誰向け)
- [手順](#手順)
  - [ウォレットを作る](#ウォレットを作る)
  - [DYDXに接続する](#dydxに接続する)
    - [アドレスに送金 + DYDXに入金](#アドレスに送金--dydxに入金)
    - [入金したETHはどうなっているのか](#入金したethはどうなっているのか)
    - [DYDX保有量とは](#dydx保有量とは)
  - [トレードする](#トレードする)
    - [APIでのトレード方法に関して](#apiでのトレード方法に関して)
    - [WEB_PROVIDER_URL とは(曖昧だが)](#web_provider_url-とは曖昧だが)
    - [client初期化](#client初期化)

# DYDXとは
Ethereumのレイヤー2に存在するDEX、無期限の先物を証拠金取引ができることが特徴。（おそらく）
大会とかやってるので楽しそう。
Serumと違って板を指すのにガス代かからないので高頻度botterが活躍できる可能性あり。(とはいえ取引手数料かかるのでvipになる必要がある)

<img width="677" alt="image" src="https://user-images.githubusercontent.com/26806928/158143368-c2b2b677-7e61-4c1a-8cdd-38381ae2aa2f.png">

# 誰向け？
基本は自分向けの覚書のようなものです、下記がわかれば読める気がする。
- 海外取引所にて取引をしたことがある。
- APIを使ってトレードをしたことがある。

**何が起きても自己責任でお願いします。**

# 手順
`あくまで手順のうちの一つでしかないので、最良の手段であることは保証しません。`

## ウォレットを作る
まずウォレットとはなんなのかみたいな話になりますね。

[ここなど](https://book.ethereum-jp.net/meteor_dapp/simple_ether_wallet)を参照するとウォレットはアドレスからアドレスへtokenを送るためのDappで、実際に送金などが行われてトークンが溜まったことになっている場所は単にアドレスと呼ぶのが正しそうです。
なのでウォレットは既存のもの(metamaskとか)を使って、ここではアドレスを作ります。
メタマスクでアドレスを作成することが可能なようなのでメタマスクを使っていきます。
手順は下記になります。
- metamaskの[Chrome拡張](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en)を入れる
- 導入した拡張機能に従ってアドレスを作成。(メタマスク側の注意をよく読みましょう)

## DYDXに接続する
アドレスを作ったので、Chrome拡張を導入したブラウザでdydxにアクセスして接続を試みてみます。

<img width="329" alt="image" src="https://user-images.githubusercontent.com/26806928/158330874-62c7385b-ad6a-4df0-8527-011ac6990488.png">

すっからかんなので蹴られた。

### アドレスに送金 + DYDXに入金

ETHを該当のアドレスに対して送り、DYDXに再接続、取引画面にて入金ボタンを押した後。

<img width="527" alt="image" src="https://user-images.githubusercontent.com/26806928/158344538-5a60f8ef-2da2-4c04-99e8-f2b940309f90.png">

### 入金したETHはどうなっているのか
ETHのままもたれるとどこかでETHをヘッジする必要が生まれる。

<img width="656" alt="image" src="https://user-images.githubusercontent.com/26806928/158344242-041c8344-c0cc-4740-bddd-0e028018afb6.png">

USDCに変換されるのであまり気にすることなさそう。

### DYDX保有量とは
大会に参加するにはDYDXを100枚持つ必要がある。
下記の疑問があった。
- 入金したトークンで取引所内で買って持っておくのか。
- 接続したアドレスが保有していればいいのか。
結論としては後者、接続したアドレスにDYDXを送金するとカウントされた。

<img width="1051" alt="image" src="https://user-images.githubusercontent.com/26806928/158345441-1feea059-3468-45fe-978a-e24256edd9ec.png">

## トレードする
uiでは以上でトレード可能。

### APIでのトレード方法に関して

DYDXのアカウントの実態はウォレットになるので、CEXに比べて認証が少し特徴的になる。

[公式のAPI仕様](https://docs.dydx.exchange/?python#authentication)

要点は下記
- 認証に段階がある(鍵を作るための認証等)
  - eth_key認証
    - 一番偉い、stark_keyとapi_keyを生み出すことが可能。
    - メタマスクのアカウントの詳細から作成可能。
  - stark_key認証
    - api_keyでできない認証を行う。
      - トレードを出すAPIはこの認証が必要。
  
        <img width="200" alt="image" src="https://user-images.githubusercontent.com/26806928/158551378-69996739-0983-431f-b6a3-838ccce64bf6.png">

  - api_key認証
      - 慣れ親しんでいるものに近い。
- Pythonクライアントでstark_keyとapi_keyを作る関数をcallできる。
  - `pip install dydx-v3-python`


方針としては eth_key認証にてstark_keyとapi_keyを作成、それを保存してトレードすることになりそう。ネットで拾ったサンプルコードを置きます。

```make_key.py
from dydx3 import Client
from dydx3.constants import API_HOST_MAINNET
from dydx3.constants import NETWORK_ID_MAINNET
from web3 import Web3

WEB_PROVIDER_URL = "https://mainnet.infura.io/v3/ hogehoge"


def generate_l2_key(eth_address: str, eth_private_key: str) -> str:
    client = Client(
        network_id=NETWORK_ID_MAINNET,
        host=API_HOST_MAINNET,
        default_ethereum_address=eth_address,
        eth_private_key=eth_private_key,
        web3=Web3(Web3.HTTPProvider(WEB_PROVIDER_URL)),
    )

    return client.onboarding.derive_stark_key()


def generate_api_key(eth_address: str, eth_private_key: str) -> str:
    client = Client(
        network_id=NETWORK_ID_MAINNET,
        host=API_HOST_MAINNET,
        default_ethereum_address=eth_address,
        eth_private_key=eth_private_key,
        web3=Web3(Web3.HTTPProvider(WEB_PROVIDER_URL)),
    )

    return client.onboarding.recover_default_api_key_credentials(eth_address)


if __name__ == "__main__":
    # read key and secret from environment variable file
    eth_public_address = " eth の wallet addr "
    eth_private_key = (
        "該当のaddrのプライペートkey"
    )
    stark_private_key = generate_l2_key(eth_public_address, eth_private_key)
    print(stark_private_key)

    api_key = generate_api_key(eth_public_address, eth_private_key)
    print(api_key)
```


### WEB_PROVIDER_URL とは(曖昧だが)
オンチェーンのコントラクトを実行するためのhttpの受口と認識している、
0からnodeを立ててlocalでそちらを叩くこともおそらく可能だが面倒なのでnodeを貸してくれるサービスがある。下記ページで `https://mainnet.infura.io/v3/ hogehoge` を取得できる。

https://infura.io/

### client初期化

以上を済ませると下記のようにclientを初期化できる。

position_idはよしなに再利用してください。

```init.py
self.client = dydxClient(
    network_id=NETWORK_ID_MAINNET,
    host=API_HOST_MAINNET,
    default_ethereum_address=cred["ETHEREUM_ADDRESS"],
    web3=Web3(Web3.HTTPProvider(cred["WEB_PROVIDER_URL"])),
    api_key_credentials=cred["API_KEY_DICT"],
)
self.client.stark_private_key = cred["STARK_PRIVATE_KEY"]
acc = self.client.private.get_account()
self.position_id = acc.data["account"]["positionId"]
```

以上、対戦よろしくお願いします。