Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flow のリソース指向プログラミング言語 Cadence 入門/Flow Cadence I...

Ara
April 12, 2020

Flow のリソース指向プログラミング言語 Cadence 入門/Flow Cadence Introduction

Ara

April 12, 2020
Tweet

More Decks by Ara

Other Decks in Programming

Transcript

  1. Flow の特徴 4 ブロックチェーンの処理を 4種類のノードに分割する ことで、ネットワークの パフォーマンスを改善 • トランザクション収集 •

    コンセンサス(PoS) • 計算 • 検証 https://medium.com/dapperlabs/enter-the-octagon-ufc-on-flow-brings-mma-to-crypto-480618408510 ※上記に加えて Observer ノードも存在する
  2. Libra の Move 言語に発想を得ている 6 • リソースオブジェクト ◦ 線形型 =

    宣言したものは必ず使わなければならない → 増えたり、なくなったりしない → ブロックチェーン上の所有権の管理に最適 • トランザクションにスクリプトを書ける
  3. リソースの利点 12 • 言語レベルで制限されたセキュアなコード(最小権限の原則) • 副次的な利点: ◦ 所有権のカスタマイズが容易 (例えば EIP-998

    は既存 ERC-721 に適用できない) ◦ ストレージ利用料の徴収が容易 (Ethereum の State Rent は既存 ERC-721 に適用できない) ◦ 再入性バグが発生しない
  4. Flow でコントラクトを実行する流れ 17 1. コントラクトのコードを書く 2. コントラクトをデプロイする → 実行したアカウントのストレージにデプロイされる 3.

    トランザクションのコードを書く 4. トランザクションを実行する (実行したアカウントで署名することになる) → 結果は、ログ記録 and/or アカウントのストレージに保管される
  5. コントラクトの書き方 20 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } 最もシンプルな NFT のコントラクト
  6. コントラクトの書き方 21 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } コントラクトの定義 アクセス修飾子 contract コントラクト名 { … }
  7. コントラクトの書き方 22 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } コントラクトデプロイ時の初期処理
  8. コントラクトの書き方 23 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } リソースの定義 アクセス修飾子 resource リソース名 { … }
  9. コントラクトの書き方 24 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } リソースオブジェクト生成時の初期処理
  10. コントラクトの書き方 25 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } アクセス修飾子 all ≒ public(他に account, contract, self がある)
  11. コントラクトの書き方 26 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } 変数の宣言。Swift に似ている let はイミュータブル、var はミュータブル 型: - Bool - Int8, Int16 …, Int256 - UInt8, UInt16 …, UInt256 - Word8, Word16, Word32, Word64 - Fix64 - UFix64 - Address - AnyStruct - AnyResource
  12. コントラクトの書き方 27 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } ここからが Cadence の特徴的なところ!
  13. コントラクトの書き方 28 access(all) contract NonFungibleToken { access(all) resource NFT {

    access(all) let id: UInt64 access(all) var metadata: {String: String} init(initID: UInt64) { self.id = initID self.metadata = {} } } init() { let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1) destroy oldNFT } } NFT リソースのオブジェクトを生成して、 実行しているアカウントのストレージに保存する このとき、もともとこの場所にあるかもしれない リソースオブジェクトを押し出して変数に移動する
  14. コントラクトの書き方 30 let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1)

    リソースオブジェクトを代入する(=)ときは この特別な移動演算子を使わなければならない 移動演算子を複数回使った式は、 右から左に向かって解釈される
  15. コントラクトの書き方 31 let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1)

    アカウントのストレージ(ストレージの storage 領域)には リソースの型をキーとしたマップが用意されている リソースの型に応じた場所に、リソースオブジェクトを格納できる
  16. コントラクトの書き方 32 let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1)

    リソースオブジェクトは上書きできないため、 移動演算子を使うときは、移動先にある(かもしれない) リソースオブジェクトを、明示的に他の場所に移動しなければならない
  17. コントラクトの書き方 33 let oldNFT <- self.account.storage[NFT] <- create NFT(initID: 1)

    destroy oldNFT リソースオブジェクトを削除する構文 リソースは線形論理と呼ばれる考え方で設計されており、 プログラム内で宣言したオブジェクトは、 プログラム終了までに必ず消費(どこかに格納 or 削除)する必要がある
  18. NFT を保持する Collection リソース 41 access(all) contract NonFungibleToken { access(all)

    resource NFT { … } access(all) resource Collection { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } destroy() { destroy self.ownedNFTs } } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } }
  19. NFT を保持する Collection リソース 42 access(all) contract NonFungibleToken { access(all)

    resource NFT { … } access(all) resource Collection { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } destroy() { destroy self.ownedNFTs } } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } ID と NFT リソースオブジェクトを保持するマップ
  20. NFT を保持する Collection リソース 43 access(all) contract NonFungibleToken { access(all)

    resource NFT { … } access(all) resource Collection { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } destroy() { destroy self.ownedNFTs } } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } リソースオブジェクトを入れる変数の型を書くときは 「@」をつけなければならない(視覚化が目的) ID と NFT リソースオブジェクトを保持するマップ リソースオブジェクトを入れる変数に代入するときは 移動演算子「<-」を使わなければならない(視覚化が目的)
  21. NFT を保持する Collection リソース 44 access(all) contract NonFungibleToken { access(all)

    resource NFT { … } access(all) resource Collection { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } destroy() { destroy self.ownedNFTs } } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } この Collection リソースはリソースオブジェクトを保 持しているため、自身が削除されるときには、 保持しているリソースオブジェクトを 明示的に削除または移動しなければならない
  22. NFT を保持する Collection リソース 45 access(all) contract NonFungibleToken { access(all)

    resource NFT { … } access(all) resource Collection { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } destroy() { destroy self.ownedNFTs } } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } }
  23. NFT を送受信する機能を提供する 47 Storage[Collection] ・ディクショナリ変数 #1
 #2
 : ・withdraw() 関数

    ・deposit() 関数 Storage[Collection] 他のアカウントの ストレージは直接 変更できない!
  24. NFT を送受信する機能を提供する 48 Storage[Collection] ・マップ変数 #1
 #2
 : ・withdraw() 関数

    ・deposit() 関数 Storage[Collection] 他のアカウントの ストレージは直接 変更できない! どうするか?      
  25. NFT を送受信する機能を提供する 49 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 そもそも、送付先アカウントに Collection のリソースオブジェクト がないので、まずこれを作るための 関数を用意する Storage[Collection]
  26. NFT を送受信する機能を提供する 50 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code 送付先アカウントにこれを 呼んでもらって、ストレージ に空のリソースオブジェクト を作ってもらう createEmptyCollection() 関数 Storage[Collection]
  27. NFT を送受信する機能を提供する 51 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code 送付先アカウントにこれを 呼んでもらって、ストレージ に空のリソースオブジェクト を作ってもらう (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 createEmptyCollection() 関数 Storage[Collection]
  28. NFT を送受信する機能を提供する 52 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 ストレージのNFTを操作する ためのインターフェースを 用意する (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 Storage[Collection]
  29. NFT を送受信する機能を提供する 53 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 このインターフェースを、 送付先アカウントの Published に入れてもらう Storage[Collection] Published 参照
  30. NFT を送受信する機能を提供する 54 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 これで ようやく 準備完了 Storage[Collection] Published
  31. NFT を送受信する機能を提供する 55 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 Storage[Collection] Published まず withdraw で NFT を引き出して…
  32. NFT を送受信する機能を提供する 56 Storage[Collection] #1
 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数

    Code createEmptyCollection() 関数 (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 まず withdraw で NFT を引き出して… Storage[Collection] Published
  33. NFT を送受信する機能を提供する 57 Storage[Collection] ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 Code

    createEmptyCollection() 関数 (空) ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 送信先アカウントの Published にある deposit を実行する (空) Storage[Collection] Published
  34. NFT を送受信する機能を提供する 58 Storage[Collection] ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 Code

    createEmptyCollection() 関数 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 NFTReceiver インターフェース - deposit() 関数 送信先アカウントの Published にある deposit を実行する (空) (空) Storage[Collection] Published
  35. NFT を送受信する機能を提供する 59 Storage[Collection] ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 Code

    createEmptyCollection() 関数 Storage[Collection] #1 ・withdraw() 関数 ・deposit() 関数 ・ディクショナリ変数 NFTReceiver インターフェース - deposit() 関数 Published NFTReceiver インターフェース - deposit() 関数 (空) 無事にNFTを送信できた
  36. 拡張した NFT コントラクトの全体 60 access(all) contract NonFungibleToken { access(all) resource

    NFT { … } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } }
  37. 61 access(all) contract NonFungibleToken { access(all) resource NFT { …

    } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } リソースのインターフェースの定義 アクセス修飾子 resource interface インターフェース名 { … } 拡張した NFT コントラクトの全体
  38. 62 access(all) contract NonFungibleToken { access(all) resource NFT { …

    } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } リソースのインターフェースの定義 アクセス修飾子 resource interface インターフェース名 { … } 関数の定義(インターフェース内は実装はなし) アクセス修飾子 fun 関数名 { … } 拡張した NFT コントラクトの全体
  39. 63 access(all) contract NonFungibleToken { access(all) resource NFT { …

    } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } リソース内の withdraw 関数と deposit 関数 拡張した NFT コントラクトの全体
  40. 64 access(all) contract NonFungibleToken { access(all) resource NFT { …

    } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } コントラクト内の createEmptyCollection 関数 (アクセス修飾子が access(all) なので、デプロイされて  いるアカウントから読み込むと誰でも実行できる) 拡張した NFT コントラクトの全体
  41. 65 access(all) contract NonFungibleToken { access(all) resource NFT { …

    } access(all) resource interface NFTReceiver { access(all) fun deposit(token: @NFT) } access(all) resource Collection: AnyResource{NFTReceiver} { access(all) var ownedNFTs: @{UInt64: NFT} init () { self.ownedNFTs <- {} } access(all) fun withdraw(withdrawID: UInt64): @NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") return <-token } access(all) fun deposit(token: @NFT) { let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } destroy() { destroy self.ownedNFTs } } access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } init() { let oldCollection <- self.account.storage[Collection] <- create Collection() destroy oldCollection } } 結果が空だったときにエラーにするための構文 拡張した NFT コントラクトの全体
  42. トランザクションの書き方 67 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } 先ほどの NFT コントラクトで、送付先アカウントが最初に実行するトランザクション
  43. トランザクションの書き方 68 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } はじめに、デプロイ済みコントラクトを、 デプロイされているアカウントから読み込む import コントラクト名 from アカウントのアドレス
  44. トランザクションの書き方 69 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } トランザクションの定義 transaction { … } トランザクションには下記を含められる - prepare(acct: AuthAccount) { … }  トランザクションを実行したアカウント  のストレージを参照&変更できる - execute { … }  基本的にメインの処理をここに書く.  引数はなく、トランザクション内に  宣言した変数のみ参照・変更できる  (変数は prepare で中身を入れる) - post { … }  事後の確認処理をここに書ける
  45. トランザクションの書き方 70 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } 空の Collection リソースオブジェクトを作って、 実行アカウントのストレージに入れる
  46. トランザクションの書き方 71 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } 空の Collection リソースオブジェクトを作って、 実行アカウントのストレージに入れる トランザクション内でリソースの型を指定する際は コントラクト名.リソース名 と記述する (おそらく名前の競合を避けるため)
  47. トランザクションの書き方 72 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } トランザクション実行のログ(これはオフチェーン)
  48. トランザクションの書き方 73 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } 実行アカウントの Published 領域に、 自分の Collection リソースへの参照を入れる
  49. トランザクションの書き方 74 import NonFungibleToken from 0x01 transaction { prepare(acct: AuthAccount)

    { let collection <- NonFungibleToken.createEmptyCollection() let oldCollection <- acct.storage[NonFungibleToken.Collection] <- collection destroy oldCollection log("Collection created for account 1") acct.published[&AnyResource{NonFungibleToken.NFTReceiver}] = &acct.storage[NonFungibleToken.Collection] as &AnyResource{NonFungibleToken.NFTReceiver} log("Reference published") } } Published 領域には、参照のみ入れられる 参照は「&」をつけて明示する 上の処理で作った自分の Collection リソースオブジェクトの 参照を、特定の関数だけにしたインターフェースで公開する
  50. 参考 79 • Introducing Flow, a new blockchain from the

    creators of CryptoKitties https://medium.com/dapperlabs/introducing-flow-a-new-blockchain-from-the-creators-of-cr yptokitties-d291282732f5 • Resources: Programming Ownership on The Blockchain - By Dieter Shirley https://hackernoon.com/resources-programming-ownership-on-the-blockchain-lzb832d1 • Flow Tutorials https://docs.onflow.org/docs • What is Move language - Speaker Deck https://speakerdeck.com/nakajo2011/what-is-move-language