###### tags: `BCALI`
# ERC721規格勉強
## 対象ライブラリ
### OpenZeppelin
**github**(https://github.com/OpenZeppelin/openzeppelin-contracts)
### Provable
**github**(https://github.com/provable-things/ethereum-api)
## OpenZeppelin
### Core
#### IERC721
##### FUNCTIONS
**balanceOf(owner)**
`owner`のアカウントの残高を返します。
**ownerOf(tokenId)**
`tokenId`トークンの所有者を返します。
要件:
* `tokenId` 存在する必要があります。
**safeTransferFrom(address from, address to, uint256 tokenId, bytes data)**
`tokenId`トークンを`from`から`to`に安全に転送します。トークンの受信者がERC721プロトコルを認識していることを確認して、トークンが永久にロックされるのを防ぎます
要件:
* `from`の値をブランクにすることはできません。
* `to`の値をブランクにすることはできません。
* `tokenId`トークンが存在し、`from`によって所有されている必要があります。
* 呼び出し元が`from`ではない場合は、`approve`によってこのトークンの移動が所有者によって許可されている必要があります。`setApprovalForAll`を参照。
* `to`送信先にスマートコントラクトアドレスを参照する場合、`IERC721Receiver.onERC721Received`によって安全な転送時に呼び出されるように実装する必要があります。
`Transfer`イベントを実装する必要があり、実行します。
**approve(to, tokenId)**
トークンを別のアカウントから`to`に転送する`tokenId`許可を与えます。トークンが転送されると、承認はクリアされます。
一度に承認できるアカウントは1つだけなので、ブランクを承認すると、以前の承認がクリアされます。
要件:
* 代理人はトークンを所有しているか、所有者から承認されたオペレーターである必要があります。
* `tokenId`が存在する必要があります。
* `Approval`イベントを実装する必要があり、実行します。
**getApproved(tokenId)**
`tokenId`に紐づいたトークンが`approve`(上記)によって承認されたアカウントを返します。
要件:
* `tokenId` が存在する必要があります。
**setApprovalForAll(operator, approved)**
`operator`代理人を承認または削除します。(本来のトークン所有者)承認された者は呼び出し側(本来の所有者)が所有するすべてのトークンについて`safeTransferFrom`を行うことができます。
要件:
* `operator`を呼び出し元にすることはできません。常にこの関数の呼び出しは本来の所有者によって行われます。
* `ApprovalForAll`イベントを実装する必要があり、発行します。
**isApprovedForAll(owner, operator)→ bool**
`operator`に対して、すべてのアセットの管理が`owner`(本来の所有者)によって許可されている場合にtrueが戻ります。
#### イベント
**Transfer(from, to, tokenId)**
`tokenId`に紐づけられたトークンが`from`から`to`に転送されるときに発行されます。
**Approval(owner, approved, tokenId)**
トークンの管理を`owner`が`tokenId`について`approved`にしたときに発行されます。
**ApprovalForAll(owner, operator, approved)**
すべての資産を管理するために`owner`(本来の所有者)によって`(approved)`を通じて、`operator`を有効または無効にしたときに発行されます。
#### IERC721Metadata
##### 関数
**name()** → string
トークンコレクション名を返します。
**symbol()** → string
トークンコレクションシンボルを返します。
**tokenURI(tokenId)** → string
`tokenId`に紐づけられたトークンのURI(Uniform Resource Identifier)を返します。
#### IERC721Enumerable
##### 関数
**totalSupply()**
コントラクトによって保存されたトークンの合計量を返します。
**tokenOfOwnerByIndex(owner, index)**
`owner`指定された`index`トークンリストで所有されているトークンIDを返します。`balanceOf`と一緒に使用して、すべてnの`owner`が所有するトークンを列挙します。
**tokenByIndex(index)**
コントラクトによって`index`に保存されたすべてのトークンの`tokenId`を返します。`totalSupply`と一緒に使用して、すべてのトークンを列挙します。
#### ERC721
##### 関数
**constructor(string name_, string symbol_)** → string
トークンコレクションに`name`と`symbol`を設定して、コントラクトを初期化します。
**baseURI()** → string
`_setBaseURI`を介して設定されたベースURIを返します。これは`tokenURI`、各トークンのURIにプレフィックスとして、またはトークンIDに特定のURIが設定されていない場合は`tokenId`に自動的に追加されます。
**_exists(uint256 tokenId)** → bool
指定された`tokenId`が既に存在するかどうかを返します。
トークンは経由所有者または`approve`か`setApprovalForAll`によって承認済みのアカウントで管理することができ xます。
トークンは、ミントされると存在し始め(`_mint`)、破壊されると存在しなくなります(`_burn`)。
**_isApprovedOrOwner(address spender, uint256 tokenId) → bool**
`spender`が`tokenId`について管理を許可されているかどうかを返します。
要件:
* `tokenId`が存在する必要があります。
**_safeMint(address to, uint256 tokenId)**
安全にミントし、`tokenId`を発行して、`to`に転送します。
要件:
* `tokenId`が既に存在してはなりません。
* `to`としてスマートコントラクトを参照する場合は、`IERC721Receiver`,`onERC721Received`を実装する必要があります。これは、安全な転送を行うために呼び出されます。
*`Transfer`イベントを発行します。
**_safeMint(address to, uint256 tokenId, bytes _data)**
`_safeMint`と同じですが、`IERC721Receiver`.`onERC721Received`において、契約の受信者に`data`が転送される追加のパラメータがあります。
**_burn(uint256 tokenId)**
`tokenId`を削除します。
要件:
* `tokenId`が存在する必要があります。
**_setTokenURI(uint256 tokenId, string _tokenURI)**
`tokenId`に対して、`_tokenURI`を設定します。
要件:
* `tokenId`が存在する必要があります。
#### IERC721Receiver
##### 関数
**onERC721Received(operator, from, tokenId, data)**
`tokenId`を持つ`IERC721`について`operator`や`from`によって`IERC721.safeTransferFrom`のコントラクトでトークンが転送されるたびに呼び出されます。
### Contracts
#### Pausable
##### 修飾子
**whenNotPaused()**
コントラクトが一時停止されていない場合にのみ関数を呼び出し可能にする修飾子。
**whenPaused()**
コントラクトが一時停止されている場合にのみ関数を呼び出し可能にする修飾子。
##### 関数
**constructor()**
一時停止されていない状態でコントラクトを初期化します。
**paused()** → bool
コントラクトが一時停止されている場合はtrueを返し、それ以外の場合はfalseを返します。
**_pause()**
コントラクトを停止状態にするトリガーです。
要件:
* 停止状態のコントラクトには使用できません。
**_unpause()**
通常の状態に復帰します。
要件:
* 停止状態のコントラクトにのみ有効です。
##### イベント
Paused(account)
`account`によって、一時停止がトリガーされた際に実行されます。
Unpaused(account)
`acccount`によって、一時停止状態が解除されると実行されます。
## Provable
### データソースについて
データソースは、信頼できるデータプロバイダーとして、Webサイト、WebAPIなどからデータを取得します。取得可能なデータについては以下のデータソースが提供されています。
**URL**:任意のWebページまたはHTTPAPIエンドポイントへのアクセスを有効にします。
**WolframAlpha**:WolframAlpha計算エンジンへのネイティブアクセスを可能にします。
**IPFS**:IPFSファイルに保存されているすべてのコンテンツへのアクセスを提供します。
**random**:Ledger NanoSで実行されている安全なアプリケーションからの改ざんされていないランダムバイトを提供します。
**computation**: 任意の計算の結果を提供します。
### クエリ
**`query: [ parameter_1, parameters_2, ...];`**
最初のパラメーターは、最初のパラメーターはメイン引数であり、通常は必須です。たとえば、URLデータソースタイプの場合、最初の引数は、リソースが存在する予想URLです。最初の引数のみが存在する場合、URLデータソースはHTTPGETが要求されたと見なします。オプションの2番目のパラメーターには、HTTPPOSTリクエストのデータペイロードが含まれている必要があります。
クエリの中間結果を解析する必要がある場合があります。たとえば、JSONAPI応答の正確なフィールドを抽出するためです。したがって、クエリでは、適用する解析ヘルパーを指定することもできます。
### URLデータについて
URLデータソースの種類は、インターネット上の任意のAPIやWebページへのアクセスを可能にします。HTTPGETリクエストとHTTPPOSTリクエストの両方をサポートします。クエリでパラメータが1つだけ指定されている場合、サービスはデフォルトでHTTPGETリクエストを実行します。2番目のパラメーターが指定されている場合、サービスはHTTP POSTリクエストを実行し、2番目のパラメーターをデータとして送信します。2番目のパラメーターが有効なJSONである場合、そのように投稿されることに注意する必要があります。
### 関数
**provable_query**
データのリクエストを行う単純なクエリです。
サポートされる引数の数とタイプはデータソースによって変化(今回のケースはURLのみと思われる)
要件:
* URL・IPFSのようなデータソースの指定が必要です。
**_callback**
オンチェーン上の情報やオフチェーン上のデータについて、自律的に定期のチェックを行うことができます。(基本的には推奨されていない)
## 考慮事項
* 上記で紹介したライブラリについては、Ethereumが公式にリリースしているものではなくサードパーティが提供しているものであるため、アップデートなどはEthereumやSolidityのバージョンに関係なく行われる可能性があります。
* アップデートが起こった場合、コントラクトが正常に動かない可能性があるため、定期的に確認する必要があります。
* また、probableについてはsolidity ver0.4以降は更新が行われていないため、solidityのメジャーアップデートが起こった場合は、逐次自分でアップデートする必要があります。
* 元の所有者(事務所など)に金銭を戻すのかどうか。