自作のERC721TokenをOpenSeaに対応させる

#はじめに
自作のアイテムを市場でトレードしたい場合、いわゆる「板」と言われる売買機能を作る必要がありますが、
サービス自体のアプリケーションを作ることに加えて、取引の機能をつくるのはとても大変です。
また他のゲームなどと交換やトレードを行うためには、加えて、他のゲームのアイテム情報などを取り込む必要があります。
OpenSeaを使うと、自作のERC721トークンを売買することができるようになります。今回は自作のアイテムをOpenSeaで取り扱い始めるまでの覚え書きです。

#ドキュメント
基本的な使い方は下記のドキュメントを参照してください。
https://docs.opensea.io/docs/1-structuring-your-smart-contract

#手順

##1.token用のjsonのendpointを用意します.
下記のような形でjsonを用意します。
attributesなどの項目は、OpenSea上に表示するパラメーターで、
表示方法はdisplay_typeなどで変えることができます。
(
この辺りのお作法は本家の開発ガイドを参照ください
https://docs.opensea.io/docs/2-adding-metadata
)

```
app.get('/opensea/tokens/:id', function (req, res) {
    res.json(
{
    "attributes": [{
        "trait_type": "base",
        "value": "A"
    }, {
        "trait_type": "rarity",
        "value": 5
    }, {
        "display_type": "resouce_number",
        "value": 10
    }, {
        "display_type": "resouce_percentage",
        "value": 5
    }, {
        "display_type": "number",
        "trait_type": "generation",
        "value": 1
    }],
    "description": "find new planet",
    "external_url": "http://planettravelers.net/planets/1",
    "image": "http://planettravelers.net/planet_img_001.png",
    "name": "CAB3X"
}
);
});
```

##2.ERC721のコントラクトを用意し、baseTokenURI()で1のendpointを返すように設定します。


```
pragma solidity ^0.4.24;

//import 'openzeppelin-solidity/contracts/token/ERC721/ERC721Token.sol';
//import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';

import "./ERC721Token.sol";
import "./Ownable.sol";
import "./Strings.sol";

/**
 * @title Creature
 * OpenSea Creature - a contract for a non-fungible creature.
 */
contract PlanetToken is ERC721Token, Ownable {
  address proxyRegistryAddress;

  constructor(address _proxyRegistryAddress) ERC721Token("PlanetToken", "PLT") public {
    proxyRegistryAddress = _proxyRegistryAddress;
  }

  function mint(address _to, uint256 _tokenId) public {
    super._mint(_to, _tokenId);
  }

  /**
   * @dev Returns an URI for a given token ID
   */
  function tokenURI(uint256 _tokenId) public view returns (string) {
    return Strings.strConcat(
        baseTokenURI(),
        Strings.uint2str(_tokenId)
    );
  }
  
  function baseTokenURI() public view returns (string) {
    return "http://planettravelers.net/opensea/tokens/";
  }

  /**
   * Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings.
   */
  function isApprovedForAll(
    address owner,
    address operator
  )
    public
    view
    returns (bool)
  {
    // Whitelist OpenSea proxy contract for easy trading.
    ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
    if (proxyRegistry.proxies(owner) == operator) {
        return true;
    }

    return super.isApprovedForAll(owner, operator);
  }
}

contract OwnableDelegateProxy { }

contract ProxyRegistry {
    mapping(address => OwnableDelegateProxy) public proxies;
}

```

##2-2proxyRegistryAddressとは

https://docs.opensea.io/discuss/5d4a942564beec007431f1af
引用：
>It depends on the network you're deploying to. It's 0xf57b2c51ded3a29e6891aba85459d600256cf317 on Rinkeby and 0xa5409ec958c83c3f309868babaca7c86dcb077c1 on mainnet. See https://github.com/ProjectOpenSea/opensea-creatures/blob/master/migrations/2_deploy_contracts.js#L7-L12 for an example of conditionally setting the proxy registry address.





#3.mintしてコインを作成します。
<img width="908" alt="スクリーンショット 2018-12-17 18.49.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/d7e5fd63-cf02-17ee-e8ff-28babc260c4a.png">


#4.アクセスする

>https://rinkeby.opensea.io/assets/contract_address/token_id
>(例)https://rinkeby.opensea.io/assets/0x9368672605133f7841024defa8c67295b236b62b/3
>cacheを消す場合は、?force_update=trueをつける
>他のsample https://docs.opensea.io/reference#retrieving-bundles


<img width="1144" alt="スクリーンショット 2018-12-17 18.36.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/938ebd4e-2989-a021-ec8f-606ea3483be5.png">

<img width="1075" alt="スクリーンショット 2018-12-17 18.36.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/7037cc2f-c766-cc92-586b-fc69914b7b49.png">

#5.売買を試してみる

FixedPrice,Auction,Bundleの中から販売方法を選択することができます。

<img width="1144" alt="スクリーンショット 2018-12-17 18.41.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/fdd78eab-1ac0-a3ff-fb9a-0095a9d65803.png">

#6.storeのtopを作成する
アイテムが属するサービスのtop画面を用意することができます。
作成方法は、tokenが管理されているcontractを入力し、topに表示される画像を設定するだけで作成できます。

Create画面
https://rinkeby.opensea.io/get-listed/step-two

説明
https://docs.opensea.io/docs/4-backfilling-items




#7.雛形を使ってとりあえず試したい場合の最短手順..

```
//nodeのversionを決める
$ nodebrew use v9.11.1
$ git clone https://github.com/ProjectOpenSea/opensea-creatures 
$ cd opensea-creatures 

//open-zippelinをinstallする
$ npm install

//remixdを立ち上げ
$ remixd -s ./ --remix-ide https://remix.ethereum.org

//deployとmintを行う。
//mint時のproxyRegistoryAddressはこちらを参照(networkによって異なる)
//https://docs.opensea.io/discuss/5d4a942564beec007431f1af
deploy.TradeableERC721Token
"AAA","AAA","0xf57b2c51ded3a29e6891aba85459d600256cf317"

//openseaを開く
https://rinkeby.opensea.io/assets/コントラクトのアドレス/1?force_update=true

```