Trouble Fetching a Minted NFT

Hello everyone!

New flow dev here—excited to be a part of the community!

I’m currently writing an api in go for a new NFT Marketplace project. Making tons of progress so far thanks to the thorough docs and demo projects; however, I’m a bit confused on capabilities.

I originally tried writing my own smart contract as a learning experience but when I began running into issues, I copy and pasted one from the kitty items demo project—for now. Unfortunately, still running into the same error. I know it’s probably something simple. Could someone point me in the right direction?

I’m trying to fetch a minted NFT with all of it’s fields but getting an “unknown member” error on “col.borrowExampleNFT”

Here’s my read_account_nft.cdc

pub struct AccountItem {
  pub let itemID: UInt64
  pub let typeID: UInt64
  pub let owner: Address

  init(itemID: UInt64, typeID: UInt64, owner: Address) {
self.itemID = itemID
self.typeID = typeID
self.owner = owner
  }
}

pub fun fetch(address: Address, id: UInt64): AccountItem? {
  if let col = getAccount(address).getCapability<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, ExampleNFT.ExampleNFTCollectionPublic}>(ExampleNFT.CollectionPublicPath).borrow() {
if let item = col.borrowExampleNFT(id: id) {
  return AccountItem(itemID: id, typeID: item.typeID, owner: address)
}
  }

  return nil
}

pub fun main(): AccountItem? {
  return  fetch(address: 0xACCOUNT_ADDRESS, id: NFT_ID)
}

and my ExampleNFT.cdc smart contract:

pub contract ExampleNFT: NonFungibleToken {

pub event ContractInitialized()
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
pub event Minted(id: UInt64, typeID: UInt64)

// Named Paths
//
pub let CollectionStoragePath: StoragePath
pub let CollectionPublicPath: PublicPath
pub let MinterStoragePath: StoragePath

// totalSupply
// The total number of ExampleNFT that have been minted
//
pub var totalSupply: UInt64

// NFT
// A Kitty Item as an NFT
//
pub resource NFT: NonFungibleToken.INFT {
    // The token's ID
    pub let id: UInt64
    // The token's type, e.g. 3 == Hat
    pub let typeID: UInt64

    // initializer
    //
    init(initID: UInt64) {
        self.id = initID
        self.typeID = 1
    }
}

// This is the interface that users can cast their ExampleNFT Collection as
// to allow others to deposit ExampleNFT into their Collection. It also allows for reading
// the details of ExampleNFT in the Collection.
pub resource interface ExampleNFTCollectionPublic {
    pub fun deposit(token: @NonFungibleToken.NFT)
    pub fun getIDs(): [UInt64]
    pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
    pub fun borrowKittyItem(id: UInt64): &ExampleNFT.NFT? {
        // If the result isn't nil, the id of the returned reference
        // should be the same as the argument to the function
        post {
            (result == nil) || (result?.id == id):
                "Cannot borrow KittyItem reference: The ID of the returned reference is incorrect"
        }
    }
}

// Collection
// A collection of KittyItem NFTs owned by an account
//
pub resource Collection: ExampleNFTCollectionPublic, NonFungibleToken.Provider,     NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
        // dictionary of NFT conforming tokens
        // NFT is a resource type with an `UInt64` ID field
        //
        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}

        // withdraw
        // Removes an NFT from the collection and moves it to the caller
        //
        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")

            emit Withdraw(id: token.id, from: self.owner?.address)

            return <-token
        }

        // deposit
        // Takes a NFT and adds it to the collections dictionary
        // and adds the ID to the id array
        //
        pub fun deposit(token: @NonFungibleToken.NFT) {
            let token <- token as! @ExampleNFT.NFT

            let id: UInt64 = token.id

            // add the new token to the dictionary which removes the old one
            let oldToken <- self.ownedNFTs[id] <- token

            emit Deposit(id: id, to: self.owner?.address)

            destroy oldToken
        }

        // getIDs
        // Returns an array of the IDs that are in the collection
        //
        pub fun getIDs(): [UInt64] {
            return self.ownedNFTs.keys
        }

        // borrowNFT
        // Gets a reference to an NFT in the collection
        // so that the caller can read its metadata and call its methods
        //
        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
            return &self.ownedNFTs[id] as &NonFungibleToken.NFT
        }

        // borrowKittyItem
        // Gets a reference to an NFT in the collection as a KittyItem,
        // exposing all of its fields (including the typeID).
        // This is safe as there are no functions that can be called on the KittyItem.
        //
        pub fun borrowKittyItem(id: UInt64): &ExampleNFT.NFT? {
            if self.ownedNFTs[id] != nil {
                let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT
                return ref as! &ExampleNFT.NFT
            } else {
                return nil
            }
        }

        // destructor
        destroy() {
            destroy self.ownedNFTs
        }

        // initializer
        //
        init () {
            self.ownedNFTs <- {}
        }
    }

    // createEmptyCollection
    // public function that anyone can call to create a new empty collection
    //
    pub fun createEmptyCollection(): @NonFungibleToken.Collection {
        return <- create Collection()
    }

    // NFTMinter
    // Resource that an admin or something similar would own to be
    // able to mint new NFTs
    //
	pub resource NFTMinter {

        // mintNFT mints a new NFT with a new ID
        // and deposit it in the recipients collection using their collection reference
        pub fun mintNFT(recipient: &{NonFungibleToken.CollectionPublic}) {

            // create a new NFT
            var newNFT <- create ExampleNFT.NFT(initID: ExampleNFT.totalSupply)

            // deposit it in the recipient's account using their reference
            recipient.deposit(token: <-newNFT)

            ExampleNFT.totalSupply = ExampleNFT.totalSupply + (1 as UInt64)
        }

    }

    // fetch
    // Get a reference to a KittyItem from an account's Collection, if available.
    // If an account does not have a ExampleNFT.Collection, panic.
    // If it has a collection but does not contain the itemID, return nil.
    // If it has a collection and that collection contains the itemID, return a reference to that.
    //
    pub fun fetch(_ from: Address, itemID: UInt64): &ExampleNFT.NFT? {
        let collection = getAccount(from)
            .getCapability(ExampleNFT.CollectionPublicPath)!
            .borrow<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic}>()
            ?? panic("Couldn't get collection")
        // We trust ExampleNFT.Collection.borowKittyItem to get the correct itemID
        // (it checks it before returning it).
        return collection.borrowKittyItem(id: itemID)
    }

    // initializer
    //
	init() {
        // Set our named paths
        //FIXME: REMOVE SUFFIX BEFORE RELEASE
        self.CollectionStoragePath = /storage/NFTCollection
        self.CollectionPublicPath = /public/NFTCollection
        self.MinterStoragePath = /storage/NFTMinter

        // Initialize the total supply
        self.totalSupply = 0

        // Create a Minter resource and save it to storage
        let minter <- create NFTMinter()
        self.account.save(<-minter, to: self.MinterStoragePath)

        emit ContractInitialized()
	}
}

Hello! Unfortunately, this is a problem with the NFT interface that we weren’t really aware of until after it was deployed. Since the borrowNFT function only returns a reference that is just typed as a NonFungibleToken.NFT, you are only able to access the id field. You have to use a custom function here, like you do with borrowKittyItem, to get the rest of the fields

shoot, my apologies, I copy-pasted the unfinished contract. I created the following function in my ExampleNFT contract but am still getting “unknown member” error on “col.borrowExampleNFT”

        pub fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? {
        if self.ownedNFTs[id] != nil {
            let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT
            return ref as! &ExampleNFT.NFT
        } else {
            return nil
        }
    }

At this point, my script and contract are essentially the same as the equivalent kitty-items contracts. Is there anything else I’m missing?

Thanks for any advice in advance
-Rob

figured it out, sorry for being rather unclear before, appreciate the help anyways!
-Rob

1 Like