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()
}
}