Open12

Cadence チュートリアル#3

飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

気づき

・関数の後ろに:で返り値の型を指定してあげるイメージ
・リソースのフィールドに値を持っていたらinit()が必要

pub contract BasicNFT {
    pub resource NFT {
        pub let id: UInt64
        pub var metadata: {String: String}

        init(initID: UInt64) {
            self.id = initID
            self.metadata = {}
        }
    }

    pub fun createNFT(id: UInt64): @NFT {
        return <-create NFT(initID: id)
    }

    init() {
        self.account.save<@NFT>(<-create NFT(initID: 1), to: /storage/BasicNFTPath)
    }
}
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

NFTの存在を確認する

気づき

・リソースの存在確認はborrowで確認することができる
・borrowの中の型はリソースなのかな??なんで&なんだろ

import BasicNFT from 0x01

transaction {
    prepare(account: AuthAccount){
        if account.borrow<&BasicNFT.NFT>(from: /storage/BasicNFTPath) != nil {
            log("token exsist")
        } else {
            log("non token exsist")
        }
    }
}
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

拡張型NFTを作成する

渡す側の実行の流れ
①NFTミント準備(NFTMinterリソース生成)
②受け皿の準備(Collectionリソース生成)
③NFTをミントして送り先に送る(トランザクションでNFTリソースの生成関数を叩いてdeposit関数を呼び出す)

渡される側の実行の流れ
①受け皿の準備(Collectionリソースの生成)
②Collectionリソースをストレージに配置

pub contract ExampleNFT {
    //NFTのリソース
    pub resource NFT { }

    //NFTを受け取るためのインターフェイス
    pub resource interface NFTReceiver { }

    //NFTを受け取るためのコレクション
    pub resource Collection: NFTReceiver { }

    //受け取る側の実行するための関数
    pub fun createEmptyCollection(): @Collection { }

    //NFTをミントするためのリソース
    pub resource NFTMinter { }
}
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

resource Collection

気づき

・辞書型でもリソースが入る場合は外側に@をつける
・代入時に<-!のように!を入れると

  pub resource Collection: NFTReceiver {
    //リソースオブジェクトが入る型の場合は外側に@をつける
    pub var ownerNFTs: @{UInt64: NFT}

    init () {
      self.ownerNFTs <- {}
    }

    pub fun withdraw(withdrawID:UInt64): @NFT {
      let token <- self.ownerNFTs.remove(key:withdrawID)!
      return <- token
    }

    pub fun deposit(token: @NFT) {
      self.ownerNFTs[token.id] <-! token
    }

    pub fun idExists(id:UInt64):Bool {
      return self.ownerNFTs[id] != nil
    }

    pub fun getIDs():[UInt64] {
      return self.ownerNFTs.keys
    }

    destroy (){
      destroy self.ownerNFTs
    }
  }

ちなみにgetIDs()はどんな感じで返ってくるか確認する。
keysっていう変数の行き先を確認したかった。

transaction

import ExampleNFT from 0x02

transaction {

    prepare(account:AuthAccount){
        let collectionRef = account.borrow<&ExampleNFT.Collection>(from: /storage/NFTCollection)
            ?? panic("error")
        log(collectionRef.getIDs())
    }

    execute {
    }

}

実行結果

16:15:09 New Transaction >> [2, 1, 3]
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

resource NFTMinter

  pub resource NFTMinter {
    pub var idCount: UInt64

      init(){
    self.idCount = 1
    }

    pub fun mintNFT():@NFT {
      var newNFT <- create NFT(initID:self.idCount)

      self.idCount = self.idCount + 1 as UInt64

      return  <- newNFT 
    }
  }
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

コード全体

pub contract ExampleNFT {
  pub resource NFT {
    pub let id: UInt64
    
    init(initID:UInt64){
      self.id = initID
    }
  }

  pub resource interface NFTReceiver {
    pub fun deposit(token:@NFT)

    pub fun getIDs():[UInt64]

    pub fun idExists(id: UInt64):Bool  
  }

  pub resource Collection: NFTReceiver {
    //リソースオブジェクトが入る型の場合は外側に@をつける
    pub var ownerNFTs: @{UInt64: NFT}

    init () {
      self.ownerNFTs <- {}
    }

    pub fun withdraw(withdrawID:UInt64): @NFT {
      let token <- self.ownerNFTs.remove(key:withdrawID)!
      return <- token
    }

    pub fun deposit(token: @NFT) {
      self.ownerNFTs[token.id] <-! token
    }

    pub fun idExists(id:UInt64):Bool {
      return self.ownerNFTs[id] != nil
    }

    pub fun getIDs():[UInt64] {
      return self.ownerNFTs.keys
    }

    destroy (){
      destroy self.ownerNFTs
    }
  }

  pub fun createEmptyCollection(): @Collection {
    return <- create Collection()
  }

  pub resource NFTMinter {
    pub var idCount: UInt64

      init(){
    self.idCount = 1
    }

    pub fun mintNFT():@NFT {
      var newNFT <- create NFT(initID:self.idCount)

      self.idCount = self.idCount + 1 as UInt64

      return  <- newNFT 
    }
  }

  init(){
    self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
    self.account.link<&{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
    self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
  }
}

飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

NFTをミントするTransaction

import ExampleNFT from 0x02

transaction {
    let receiverRef: &{ExampleNFT.NFTReceiver}
    let minterRef: &ExampleNFT.NFTMinter

    prepare(account:AuthAccount){
        self.receiverRef = account.getCapability<&{ExampleNFT.NFTReceiver}>(/public/NFTReceiver)
            .borrow()
            ?? panic("error")

        self.minterRef = account.borrow<&ExampleNFT.NFTMinter>(from: /storage/NFTMinter)
            ?? panic("error")
    }

    execute{
        let newNFT <- self.minterRef.mintNFT()

        self.receiverRef.deposit(token: <-newNFT)

        log("mint!!")
    }
}
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)
import ExampleNFT from 0x02

transaction {
    prepare(account:AuthAccount){
        let collection <- ExampleNFT.createEmptyCollection()

        account.save(<-collection, to: /storage/NFTCollection)
        log("Good Save")

        account.link<&{ExampleNFT.NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
        log("Good Link")
    }
}
飯泉一馬(いいずみかずま)飯泉一馬(いいずみかずま)

transfer code

import ExampleNFT from 0x02

transaction {
    let tmpToken: @ExampleNFT.NFT

    prepare(account:AuthAccount){
        let collectionRef = account.borrow<&ExampleNFT.Collection>(from: /storage/Collection)
            ?? panic("error")
        self.tmpToken <- collectionRef.withdraw(withdrawID:1)
    }

    execute {
        let recipient = getAccount(0x01)
        let receiverRef = recipient.getCapability<&{ExampleNFT.NFTReceiver}>(/public/NFTReceiver)
            .borrow()
            ?? panic("error")
        
        receiverRef.deposit(token: <-self.tmpToken)
        log("ID")
    }
}