10. Composable Resources

[Previous << 9. Voting Contract](https://qiita.com/flowcadence/items/284a96590784650acc3c)
[Next >> Language Reference](https://qiita.com/flowcadence/items/9b08c176d64eff402a4d)

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

このチュートリアルでは、複合的なNFTを作成、デプロイ、移動させることで、リソースが他のリソースを所有する方法を説明します。

:::note
ⓘ ACTION(操作)
このチュートリアルには、サンプルコードのみが含まれています。関連するプレイグラウンドプロジェクトはありません。ただし、このコードをコピーしてプレイグラウンドに貼り付け、テストすることは可能です。
:::
リソースを所有するリソースは、ブロックチェーンとスマートコントラクトの世界では強力な機能です。

**このチュートリアルを進める前に**、「[Getting Started](https://qiita.com/flowcadence/items/d74e796356935d409ba4)」、「[Hello, World!](https://qiita.com/flowcadence/items/8d5bce1f1feaf5404d2b)」、および「[Resources](https://qiita.com/flowcadence/items/891aaf12938b0e697ad3)」の手順に従って、プレイグラウンドとCadenceについて学んでください。

<h1 id="Resources-Owning-Resources">Resources Owning Resources</h1>

[Non-Fungible Token](https://qiita.com/flowcadence/items/ee22ed2ce344620c79da)で話題になっているNFTコレクションは、他のリソースを所有するリソースの一例です。NFTコレクションというリソースがあり、その中に保存されているNFTリソースを所有しています。所有者と参照(reference)を持つ人は誰でも、これらのリソースを移動させることができます(補足: 例としてマーケットプレイスのようなスマートコントラクトに所有者が参照を渡しているケースがあります。)が、それらがコレクション内に存在する限り、それらはコレクションに属しており、コレクションで定義されたコードがリソースを最終的に制御します。

コレクションが移動または破棄された場合、その中にあるすべてのNFTも一緒に移動または破棄されます。

コレクションの所有者がコレクションのリソース全体を他のユーザーのアカウントに転送した場合、トークンはすべて他のユーザーのアカウントに移動します。トークンは元の所有者のアカウントには残りません。これは、1ドル紙幣ではなく財布を誰かに手渡すようなものです。一般的ではありませんが、確かに可能です。

他のリソースに格納されているリソースに対しては参照を作成することはできません。 所有するリソースがそれを制御し、したがって、格納されたリソースに対する外部からの呼び出しのアクセス権限を制御します。

<h1 id="Example">Example</h1>

NFTコレクションは、リソースが他のリソースを所有できることを示す単純な例ですが、より革新的で強力なバージョンを作成することも可能です。

CryptoKitties（およびイーサリアム・ブロックチェーン上のその他のアプリケーション）の重要な特徴は、既存のアプリケーションの周りに、あらゆる開発者が新しい体験を作り出せることです。オリジナルのスマートコントラクトには、CryptoKittyのアクセサリー（帽子など）に対する具体的なサポートは含まれていませんでしたが、独立した開発者は、オリジナルのスマートコントラクトのKittiesが使える帽子を作ることができました。

以下は、この機能をCadenceで再現する方法の基本的な例です。
```ruby:KittyVerse.cdc
/* KittyVerse.cdc
 *
 * The KittyVerse contract defines two types of NFTs.
 * One is a KittyHat, which represents a special hat, and
 * the second is the Kitty resource, which can own Kitty Hats.
 *
 * You can put the hats on the cats and then call a hat function
 * that tips the hat and prints a fun message.
 *
 * This is a simple example of how Cadence supports
 * extensibility for smart contracts, but the language will soon
 * support even more powerful versions of this.
 */

access(all) contract KittyVerse {

    /* KittyHat is a special resource type that represents a hat */
    access(all) resource KittyHat {

        access(all) let id: Int
        
        access(all) let name: String

        init(id: Int, name: String) {
            self.id = id
            self.name = name
        }

        /* An example of a function someone might put in their hat resource */
        access(all) fun tipHat(): String {
            if self.name == "Cowboy Hat" {
                return "Howdy Y'all"
            } else if self.name == "Top Hat" {
                return "Greetings, fellow aristocats!"
            }

            return "Hello"
        }
    }

    /* Create a new hat */
    access(all) fun createHat(id: Int, name: String): @KittyHat {
        return <-create KittyHat(id: id, name: name)
    }

    access(all) resource Kitty {

        access(all) let id: Int

        /* place where the Kitty hats are stored */
        access(all) var items: @{String: KittyHat}

        init(newID: Int) {
            self.id = newID
            self.items <- {}
        }

        access(all) fun getKittyItems(): @{String: KittyHat} {
            var other: @{String:KittyHat} <- {}
            self.items <-> other
            return <- other
        }

        access(all) fun setKittyItems(items: @{String: KittyHat}) {
            var other <- items
            self.items <-> other
            destroy other
        }

        access(all) fun removeKittyItem(key: String): @KittyHat? {
            var removed <- self.items.remove(key: key)
            return <- removed
        }
    }

    access(all) fun createKitty(): @Kitty {
        return <-create Kitty(newID: 1)
    }
}
```

これらの定義は、Kittyリソースが帽子を所有できることを示しています。

帽子はKittyリソースの変数に格納されています。
```ruby
    /* place where the Kitty hats are stored */
    access(all) var items: @{String: KittyHat}
```
キティの帽子を脱がせ、個別に移動させることができます。または、帽子を所有するキティを移動させ、帽子はキティと一緒に移動します。

KittyとKittyHatを作成し、Kittyに帽子を保存し、次にそれをアカウントのストレージに保存します。
```ruby:create_kitty.cdc
import KittyVerse from 0x06

/* This transaction creates a new kitty, creates two new hats and
   puts the hats on the cat. Then it stores the kitty in account storage. */
transaction {
    prepare(acct: auth(SaveValue) &Account) {

        /* Create the Kitty object */
        let kitty <- KittyVerse.createKitty()

        /* Create the KittyHat objects */
        let hat1 <- KittyVerse.createHat(id: 1, name: "Cowboy Hat")
        let hat2 <- KittyVerse.createHat(id: 2, name: "Top Hat")

        let kittyItems <- kitty.getKittyItems()

        /* Put the hat on the cat! */
        let oldCowboyHat <- kittyItems["Cowboy Hat"] <- hat1
        destroy oldCowboyHat
        let oldTopHat <- kittyItems["Top Hat"] <- hat2
        destroy oldTopHat

        kitty.setKittyItems(items: <-kittyItems)

        log("The cat has the hats")

        /* Store the Kitty in storage */
        acct.storage.save(<-kitty, to: /storage/kitty)
    }
}
```

これで、キティとその帽子を一緒に移動させるトランザクションを実行し、キティからカウボーイハットを取り除き、キティに帽子を脱がせることができます。
```ruby:tip_hat.cdc
import KittyVerse from 0x06

/* This transaction moves a kitty out of storage, takes the cowboy hat off of the kitty,
   calls its tip hat function, and then moves it back into storage. */
transaction {
    prepare(acct: auth(Storage) &Account) {

        /* Move the Kitty out of storage, which also moves its hat along with it */
        let kitty <- acct.storage.load<@KittyVerse.Kitty>(from: /storage/kitty)
            ?? panic("Kitty doesn't exist!")

        /* Take the cowboy hat off the Kitty */
        let cowboyHat <- kitty.removeKittyItem(key: "Cowboy Hat")
            ?? panic("cowboy hat doesn't exist!")

        /* Tip the cowboy hat */
        log(cowboyHat.tipHat())
        destroy cowboyHat

        /* Tip the top hat that is on the Kitty */
        log(kitty.items["Top Hat"]?.tipHat())

        /* Move the Kitty to storage, which
           also moves its hat along with it. */
        acct.storage.save(<-kitty, to: /storage/kitty)
    }
}
```
このトランザクションを実行すると、次のような出力が表示されます。
```
> "Howdy Y'all"
> "Greetings, fellow aristocats!"
```
キティが動くと、その帽子も暗黙のうちに一緒に動きます。これは、帽子がキティの所有物であるためです。

<h1 id="Extensibility-is-coming">Extensibility is coming</h1>

上記は、コンポーザブルリソースの簡単な例です。この例では、KittyがHatを所有できることを明示的に言わなければなりませんでした。しかし、Cadenceでは、所有リソースが所有可能性を最初から指定していなかった場合でも、開発者が分離したリソースが所有できるタイプを宣言できる、より強力なリソース拡張性を実現する方法が(補足: Cadence version1.0で)サポートされるようになりました。

この機能は「[Attachment(アタッチメント)](https://qiita.com/flowcadence/items/4b41229869c45bc8a4df)」と呼ばれ、この強力な機能について学ぶには、ドキュメントを確認してください！


Flow Playgroundで学んだことを実践してみましょう！

翻訳元

https://cadence-lang.org/docs/tutorial/resources-compose

***
<b>[Previous << 9. Voting Contract](https://qiita.com/flowcadence/items/284a96590784650acc3c)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (10. Composable Resources)

<b>[Next >> Language Reference](https://qiita.com/flowcadence/items/9b08c176d64eff402a4d)</b>