Appending Asset into an array

Hi, I am tweaking NFT tutorial transaction to withdraw NFT which I minted and append into an array in the transaction as follows.

    execute {
        let myCollections:[@NonFungibleToken.NFT] = []
        log("NFT Minted and deposited to Account 2's Collection")
        let firstRound = self.minterRef.mintNFT(nfts: 3, recipient: self.receiverRef)
        for element in firstRound {
            log(element)
            myCollections.append(<- self.collectionRef.withdraw(withdrawID: element))
        }
    }

However, I am getting unexpected token in type: '@' at let myCollections:[@NonFungibleToken.NFT] = [].

Screenshot 2020-07-17 at 16.17.15

If I take that out, then I get missing resource annotation: @as well asincorrect transfer operation. expected `<-``

Any suggestions appreciated.

The following seems almost working except that I get loss of resource.

    execute {
        let myCollections:@[NonFungibleToken.NFT] <- []
        log("NFT Minted and deposited to Account 2's Collection")
        let firstRound = self.minterRef.mintNFT(nfts: [], recipient: self.receiverRef)
        for element in firstRound {
            log(element)
            myCollections.append(<- self.collectionRef.withdraw(withdrawID: UInt64(element)))
        }
    }

It turns out that I cannot iterate array of asset, so decided to change to use Collection.

The code has no error but when I run, I get the following error.

WARN[0048] ERR [feba0b] Execution failed:
unexpectedly found nil while forcing an Optional value 

Here is my Mint function (the rest hasnโ€™t changed)

        pub fun mintNFT(nfts: &Collection, recipient: &AnyResource{NFTReceiver}): [Int] {
            var a = 0
            var ids: [UInt64] = nfts.getIDs()
            var nftLength = ids.length

            var newIds: [Int] = []
            if nftLength == 0 {
                var newNFT <- create NFT(initID: self.idCount)
                recipient.deposit(token: <-newNFT)
                self.idCount = self.idCount + UInt64(1)
                return [Int(self.idCount)]
            }

            while a < nftLength {
                // create a new NFT
                var newNFT <- create NFT(initID: self.idCount)
                // deposit it in the recipient's account using their reference
                recipient.deposit(token: <-newNFT)
                recipient.deposit(token: <-nfts.withdraw(withdrawID: ids[a]))
                // change the id so that each ID is unique
                self.idCount = self.idCount + UInt64(1)
                newIds.append(Int(self.idCount))
                newIds.append(Int(ids[a]))
                a = a + 1
            }
            return newIds
        }

And here is the transaction

import NonFungibleToken from 0x01cf0e2f2f715450

// This transaction allows the Minter account to mint an NFT
// and deposit it into its collection.

transaction {

    // The reference to the collection that will be receiving the NFT
    let receiverRef: &{NonFungibleToken.NFTReceiver}
    // The reference to the Minter resource stored in account storage
    let minterRef: &NonFungibleToken.NFTMinter

    let collectionRef: &NonFungibleToken.Collection
    let myCollections: &NonFungibleToken.Collection
    prepare(acct: AuthAccount) {
        // Get the owner's collection capability and borrow a reference
        self.receiverRef = acct.getCapability(/public/NFTReceiver)!
                               .borrow<&{NonFungibleToken.NFTReceiver}>()!
        
        // Borrow a capability for the NFTMinter in storage
        self.minterRef = acct.borrow<&NonFungibleToken.NFTMinter>(from: /storage/NFTMinter)!
        self.collectionRef = acct.borrow<&NonFungibleToken.Collection>(from: /storage/NFTCollection)!
        let collection <- NonFungibleToken.createEmptyCollection()
        acct.save<@NonFungibleToken.Collection>(<-collection, to: /storage/MyCollection)
        self.myCollections = acct.borrow<&NonFungibleToken.Collection>(from: /storage/MyCollection)!
    }

    execute {
        let firstRound = self.minterRef.mintNFT(nfts: self.myCollections, recipient: self.receiverRef)
        for element in firstRound {
            log(element)
            self.myCollections.deposit(token:<- self.collectionRef.withdraw(withdrawID: UInt64(element)))
        }
        for element in self.myCollections.getIDs() {
            log(element)
            let secondRound = self.minterRef.mintNFT(nfts: self.myCollections, recipient: self.receiverRef)
        }
    }
}

The full code is in this commit. I think I am almost here.

Thanks.

@makoto
The error you are getting: unexpectedly found nil while forcing an Optional value comes from when you use the force-unwrap operator to unwrap an optional and it finds nil.

Whenever you are trying to borrow a reference, I would always recommend using the nil-coalescing operator instead. This way, you can include an error statement so you know which one is nil

So for the first line in the transaction, you would change it to

self.receiverRef = acct.getCapability(/public/NFTReceiver)!
                               .borrow<&{NonFungibleToken.NFTReceiver}>()
                             ?? panic("Could not borrow receiver reference")

Could you try that out? That will let you know which line it is coming from.

I get exactly the same error.

I think the error is happening at

self.myCollections.deposit(token:<- self.collectionRef.withdraw(withdrawID: UInt64(element)))

I added log() to print out line number and thatโ€™s where it throws an error

@makoto Sorry I wasnโ€™t clear, I meant to say that you should add something like that everywhere you try to borrow a reference. Youโ€™re right that this isnโ€™t from that. It is from the withdraw function because you are trying to withdraw id=2 from collectionRef instead of MyCollections

Iโ€™ve changed some code here and there:

  • Old MyCollection item is being destroyed, when transaction is executed (you probably need to rework this into check if MyCollection exists. I didnโ€™t had time to dive into the idea, just made the whole thing functional :sweat_smile:
  • withdraw method on Collection now returns Optional NFT resource. This would allow you to work with optional bindings in your transaction code later. You can read more about optional bindings here:
    https://docs.onflow.org/docs/cadence#optional-binding

This version shall work now:

1 Like