5.1 Non-Fungible Token Tutorial Part 1

[Previous << 4. Capability Tutorial](https://qiita.com/flowcadence/items/87b1cc1ff58417dc086d)
[Next >> 5.2 Non-Fungible Token Tutorial Part 2](https://qiita.com/flowcadence/items/0f791b45ca9fd289944a)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#cadenceの言語仕様を学ぶ

このチュートリアルでは、非代替性トークン（NFT）のデプロイ、保存、転送を行います。(補足: ここのコードは初心者向けにかなりイレギュラーな構成になっているため、参考程度に留めて次のチュートリアルに進んでください。次以降は実際に参考になるコードになっています。）

:::note warn
💡 TIP
このチュートリアルのスターターコードをFlow Playgroundで開きます。
https://play.flow.com/dde1e2a4-aae6-4eda-86fd-f0b0b3f53f7e
チュートリアルでは、このコードとやり取りするためにさまざまな操作を行うよう求められます。
:::
:::note
ⓘ ACTION
ユーザーにアクションを要求する指示は、常にこのような吹き出しボックス内に記載されています。ハイライトされたアクションは、コードを実行するために必要なすべてですが、言語の設計を理解するには、残りの部分を読むことも必要です。
:::
NFTはブロックチェーン技術の不可欠な要素です。NFTは、ユニークな資産の所有権を表すデジタル資産です。NFTは分割できないため、NFTの一部を取引することはできません。NFTの例としては、CryptoKitties、Top Shot Moments、とても楽しいコンサートのチケット、または馬などが考えられます。

ほとんどのスマートコントラクト言語のような中央台帳で表現するのではなく、Cadenceでは、各NFTをユーザーがアカウントに保存する[リソースオブジェクト](https://qiita.com/flowcadence/items/f9b95df70c80a90d3a20)として表現します。

これにより、NFTは[型システム](https://qiita.com/flowcadence/items/c917af1e35cd46cf6a7f)によって強制されるリソース所有権のルールから利益を得ることができます。リソースは単一の所有者しか持つことができず、複製することはできず、また、偶発的または悪意のあるプログラミングエラーによって失われることもありません。これらの保護により、所有者はNFTが安全であり、真の価値を持つ資産を表すことができることを確実に知ることができます。

現実世界におけるNFTは、資産の取引を可能にし、資産の所有者が誰であるかを証明します。Flowでは、NFTは相互運用可能であるため、アカウント内のNFTを異なるスマートコントラクトやアプリのコンテキストで使用することができます。Flow上のすべてのNFTは、Flow上のNFTの基本的なプロパティセットを定義する[Flow NFT Standard](https://github.com/onflow/flow-nft)を実装しています。このチュートリアルでは、重要な言語概念を説明するためにNFTの基本的な作成方法を教えますが、簡潔さと学習を目的としてNFT標準(NFT Standard)は使用しません。

NFTチュートリアルを完了した読者は、[NFTガイド](https://developers.flow.com/build/guides/nft)と[NFT標準GitHubリポジトリ](https://github.com/onflow/flow-nft)を参照し、完全な実用NFTがどのように作成されるかを学んでください。

NFTを快適に使いこなせるようになるために、このチュートリアルでは以下のことを学びます。
1. 基本的なNFTスマートコントラクトと型定義をデプロイする。
2. NFTオブジェクトを作成し、アカウントのストレージに保存する。
3. アカウントに複数のNFTを保存するためのNFTコレクションオブジェクトを作成する。
4. `NFTMinter`を作成し、それを使用してNFTを発行する。
5. 他の人がトークンを送信できるように、コレクションに機能(Capability)を作成する。
6. 同じ方法で別のアカウントを設定します。
7. NFT を 1 つのアカウントから別のアカウントに転送します。
8. スクリプトを使用して、各アカウントのコレクションに保存されている NFT を確認します。
:::note warn
⚠️ WARNING
このチュートリアルでは、実際に動作する非代替性トークンを実装していますが、教育目的で簡略化されているため、実際のプロジェクトで使用すべきものではないことに注意してください。標準インターフェイスと実装例については、[Flow Fungible Token Standard](https://github.com/onflow/flow-nft)を参照してください。
:::
**このチュートリアルを進める前に**、「[Getting Started](https://qiita.com/flowcadence/items/d74e796356935d409ba4)」、「[Hello, World!](https://qiita.com/flowcadence/items/8d5bce1f1feaf5404d2b)」、「[Resources](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)」、および「[Capabilities](https://qiita.com/flowcadence/items/87b1cc1ff58417dc086d)」の手順に従って、Playgroundツールの使用方法とCadenceの基本を習得することを強くお勧めします。このチュートリアルでは、それらのチュートリアルで紹介された概念を基に構築していきます。

(中略)

<h1 id="Adding-an-NFT-Your-Account">Adding an NFT Your Account</h1>

まずは、アカウントにNFTを追加する基本的なNFTスマートコントラクトについて見ていきましょう。このスマートコントラクトでは、以下の処理を行います。
1. NFTリソースタイプを使用してスマートコントラクトを作成します。
2. NFTリソースにIDフィールド、メタデータフィールド、イニシャライザー(init関数)を宣言します。
3. アカウントにNFTを保存するスマートコントラクトの初期化子(init関数)を作成します。

このスマートコントラクトでは、アカウントにNFTを保存するために、[アカウントストレージAPI](https://qiita.com/flowcadence/items/129d58ae7cb962056c6c)を使用します。

:::note
ⓘ ACTION
まず、このリンクからNon-Fungible Tokenのコントラクト、トランザクション、スクリプトが事前に読み込まれたプレイグラウンド(playground)を開いてください。
https://play.flow.com/dde1e2a4-aae6-4eda-86fd-f0b0b3f53f7e
:::
:::note
ⓘ ACTION
アカウント`0x06` を選択して`BasicNFT.cdc` を表示します。`BasicNFT.cdc`には次のコードが含まれています。
:::
```ruby:BasicNFT.cdc
access(all) contract BasicNFT {

    /* Declare the NFT resource type */
    access(all) resource NFT {
        /* The unique ID that differentiates each NFT */
        access(all) let id: UInt64

        /* String mapping to hold metadata */
        access(all) var metadata: {String: String}

        /* Initialize both fields in the initializer */
        init(initID: UInt64) {
            self.id = initID
            self.metadata = {}
        }
    }

    /* Function to create a new NFT */
    access(all) fun createNFT(id: UInt64): @NFT {
        return <-create NFT(initID: id)
    }

    /* Create a single new NFT and save it to account storage */
    init() {
        self.account.storage.save(<-create NFT(initID: 1), to: /storage/BasicNFTPath)
    }
}
```
上記のスマートコントラクトは、NFTとは整数のIDとメタデータ用のフィールドを持つリソース(resource)です。

各NFTリソースは一意のIDを持つ必要があるため、スマートコントラクトが許可しない限り、結合や複製ができません。

この設計のもう一つのユニークな特徴は、各NFTが独自のメタデータを含むことができることです。この例では、単純な文字列(`String`)から文字列(`String`)へのマッピングを使用していますが、複雑なファイル形式やその他のデータを保存できるより[リッチなバージョン](https://github.com/onflow/flow-nft#nft-metadata)を(あなたが)想像してもいいです。

NFTは他のNFTを所有することもできます！この機能は、後のチュートリアルで説明します。

<h1 id="Initializers">Initializers</h1>

```ruby
init() {
// ...
```
スマートコントラクト、リソース、構造体などのすべての複合型には、オブジェクトが最初に作成されたときにのみ実行されるオプションのイニシャライザー(init関数)を指定することができます。Cadenceでは、複合型のすべてのフィールドは明示的に初期化する必要があるため、オブジェクトにフィールドがある場合は、それらを初期化するためにこの関数を使用する必要があります。

また、スマートコントラクトは組み込みの[`self.account`](https://qiita.com/flowcadence/items/91a5ecb5812af1f98bef)フィールドを使用して、デプロイ先のアカウントのストレージに対して読み取りおよび書き込みアクセス権限も有しています。これは、[アカウント参照](https://qiita.com/flowcadence/items/5ddbb79fe8438850cf57)（`&Account`）であり、アカウントのストレージ、機能(Capability)、キー、およびスマートコントラクトなど、アカウントのあらゆる側面へのアクセスと管理が許可されています。

スマートコントラクトのイニシャライザー(init関数)では、新しいNFTオブジェクトを作成し、それをアカウントストレージに移動します。
```ruby
/* put it in storage */
self.account.storage.save(<-create NFT(initID: 1), to: /storage/BasicNFTPath)
```
ここでは、スマートコントラクトがデプロイされたアカウントのストレージオブジェクトにアクセスし、その`save`メソッドを呼び出します。また、同じ行でNFTを作成し、`save`メソッドの最初の引数として渡します。これはオブジェクトが保存される`/storage/`ドメインに保存します。

:::note
ⓘ ACTION
エディタの右上にあるデプロイボタンをクリックして、`BasicNFT`をデプロイします。
:::
これで、アカウントにNFTが作成されたはずです。確認のため、トランザクションを実行してみましょう。

:::note
ⓘ ACTION
`NFT Exists`トランザクションを開き、アカウント`0x06`を唯一の署名者として選択し、トランザクションを送信(send)します。
`NFT Exists`トランザクションは次のようになります。
:::
```ruby:NFTExists.cdc
import BasicNFT from 0x06

/* This transaction checks if an NFT exists in the storage of the given account
   by trying to borrow from it. If the borrow succeeds (returns a non-nil value), the token exists! */
transaction {
    prepare(acct: auth(BorrowValue) &Account) {
        if acct.storage.borrow<&BasicNFT.NFT>(from: /storage/BasicNFTPath) != nil {
            log("The token exists!")
        } else {
            log("No token found!")
        }
    }
}
```
ここでは、ストレージ内のNFTから直接、参照を借用(borrow)しようとしています。オブジェクトが存在すれば、borrowは成功し、オプショナルの参照は`nil`にはなりません。しかし、borrrowに失敗した場合は、オプションは`nil`になります。

"`The token exists!`"と表示されるはずです。

素晴らしい！これで、アカウントに初めてのNFTが追加されました。別のアカウントに移動してみましょう！
<h1 id="Performing-a-Basic-Transfer">Performing a Basic Transfer</h1>

これらの強力なアセットがアカウントにある場合、おそらく他のアカウントに移動させたいと思うでしょう。Cadenceではオブジェクトを転送する方法はいくつかありますが、まず最も簡単な方法をご紹介します。

また、この機会に、ご自身でコードを書いてみるといいでしょう！

:::note
ⓘ ACTION
`Basic Transfer`トランザクションを開きます。
`Basic Transfer`は次のようになっているはずです。
:::
```ruby
import BasicNFT from 0x06

/* Basic transaction for two accounts to authorize
   to transfer an NFT */

transaction {
    prepare(
        signer1: auth(LoadValue) &Account,
        signer2: auth(SaveValue) &Account
    ) {

        /* Fill in code here to load the NFT from signer1
           and save it into signer2's storage */

    }
}
```
私たちは、署名者2人の空のトランザクションを提供しました。

トランザクションが開いている間、トランザクションに署名する1つ以上のアカウントを選択できます。これは、Flowでは複数のアカウントが同じトランザクションに署名でき、プライベートストレージにアクセスできるためです。複数のアカウントが署名者として選択された場合、これは「Basice Transfer」トランザクションで示されているように、複数の署名者が表示されるようにトランザクションの署名に反映させる必要があります。

必要なのは、`signer1`のストレージからNFTを`load()`し、`signer2`のストレージに`save()`することだけです。これらの操作は以前にも使用したことがあるはずなので、理解するのはそれほど難しくないでしょう。これらのアカウント方法の例については、以前のチュートリアルに戻ってご覧ください。(補足: この方法は原始的であるため実際には利用しません。マーケットプレイスのような、より洗練したやり方が他にある為です。また、複数のアカウントをトランザクションの署名者にすることはかなり高度であり、普通のWebアプリのフロントエンドでは不可能だからです。)

また、少し下にスクロールすると、正しいコードもご覧いただけます。

こちらが、あるアカウントからNFTを読み込み、別のアカウントに保存するための正しいコードです。
```ruby
import BasicNFT from 0x06

/* Basic transaction for two accounts to authorize
   to transfer an NFT */

transaction {
    prepare(
        signer1: auth(LoadValue) &Account,
        signer2: auth(SaveValue) &Account
    ) {

        /* Load the NFT from signer1's account */
        let nft <- signer1.storage.load<@BasicNFT.NFT>(from: /storage/BasicNFTPath)
            ?? panic("Could not load NFT from the first signer's storage")

        /* Save the NFT to signer2's account */
        signer2.storage.save(<-nft, to: /storage/BasicNFTPath)

    }
}
```
:::note
ⓘ ACTION
署名者として、Account `0x06`とAccount `0x07`の両方を選択します。Account `0x06`が最初の署名者であることを確認します。
「Send」ボタンをクリックしてトランザクションを送信します。
:::
これで、NFTはアカウント`0x07`のストレージに保存されるはずです。`0x07`を署名者として「NFT Exists」トランザクションを再度実行し、アカウント内に存在していることを確認してください。

<h1 id="Enhancing-the-NFT-Experience">Enhancing the NFT Experience</h1>

ここまでで、NFTがCadenceのリソースでどのように表現できるかについて、おおよその見当はついたことでしょう。ここで、もし各NFTに異なるパスを記憶させ、マルチシグネチャのトランザクションを転送に使用することをユーザーに要求していたら、開発者およびユーザーにとって非常に使いにくいものになっていたことに、お気づきかもしれません。

そこでCadenceの真価が発揮されます。[次のチュートリアル](https://qiita.com/flowcadence/items/0f791b45ca9fd289944a)に進み、他のリソースを所有する機能(Capability)やリソース(Resource)を利用して、NFTの使いやすさと安全性を向上させる方法を確認しましょう。

翻訳元

https://cadence-lang.org/docs/tutorial/non-fungible-tokens-1

***
<b>[Previous << 4. Capability Tutorial](https://qiita.com/flowcadence/items/87b1cc1ff58417dc086d)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (5.1 Non-Fungible Token Tutorial Part 1)

<b>[Next >> 5.2 Non-Fungible Token Tutorial Part 2](https://qiita.com/flowcadence/items/0f791b45ca9fd289944a)</b>