Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add core nft view #103

Merged
merged 1 commit into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions contracts/MetadataViews.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,39 @@ pub contract MetadataViews {
pub fun getIDs(): [UInt64]
}

/// NFTView is a group of views used to give a complete picture of an NFT
///
pub struct NFTView {
pub let id: UInt64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might also want uuid in here

pub let uuid: UInt64
pub let display: Display?
pub let externalURL: ExternalURL?
pub let collectionData: NFTCollectionData?
pub let collectionDisplay: NFTCollectionDisplay?
pub let royalties: Royalties?
pub let traits: Traits?

init(
id : UInt64,
uuid : UInt64,
display : Display?,
externalURL : ExternalURL?,
collectionData : NFTCollectionData?,
collectionDisplay : NFTCollectionDisplay?,
royalties : Royalties?,
traits: Traits?
) {
self.id = id
self.uuid = uuid
self.display = display
self.externalURL = externalURL
self.collectionData = collectionData
self.collectionDisplay = collectionDisplay
self.royalties = royalties
self.traits = traits
}
}

/// Display is a basic view that includes the name, description and
/// thumbnail for an object. Most objects should implement this view.
///
Expand Down Expand Up @@ -619,4 +652,17 @@ pub contract MetadataViews {
return nil
}

pub fun getNFTView(id: UInt64, viewResolver: &{Resolver}) : NFTView {
return NFTView(
id : id,
uuid: viewResolver.uuid,
display: self.getDisplay(viewResolver),
externalURL : self.getExternalURL(viewResolver),
collectionData : self.getNFTCollectionData(viewResolver),
collectionDisplay : self.getNFTCollectionDisplay(viewResolver),
royalties : self.getRoyalties(viewResolver),
traits : self.getTraits(viewResolver)
)
}

}
6 changes: 3 additions & 3 deletions lib/go/contracts/internal/assets/assets.go

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions lib/go/templates/internal/assets/assets.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions lib/go/templates/script_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
filenameGetCollectionLength = "scripts/get_collection_length.cdc"
filenameGetTotalSupply = "scripts/get_total_supply.cdc"
filenameGetNFTMetadata = "scripts/get_nft_metadata.cdc"
filenameGetNFTView = "scripts/get_nft_view.cdc"
)

// GenerateBorrowNFTScript creates a script that retrieves an NFT collection
Expand All @@ -27,6 +28,12 @@ func GenerateGetNFTMetadataScript(nftAddress, exampleNFTAddress, metadataAddress
return replaceAddresses(code, nftAddress, exampleNFTAddress, metadataAddress, flow.EmptyAddress)
}

// GenerateGetNFTViewScript creates a script that returns the rollup NFT View for an NFT.
func GenerateGetNFTViewScript(nftAddress, exampleNFTAddress, metadataAddress flow.Address) []byte {
code := assets.MustAssetString(filenameGetNFTView)
return replaceAddresses(code, nftAddress, exampleNFTAddress, metadataAddress, flow.EmptyAddress)
}

// GenerateGetCollectionLengthScript creates a script that retrieves an NFT collection
// from storage and tries to borrow a reference for an NFT that it owns.
// If it owns it, it will not fail.
Expand Down
129 changes: 128 additions & 1 deletion lib/go/test/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestGetNFTMetadata(t *testing.T) {
exampleNFTAccountKey,
exampleNFTSigner)

t.Run("Should be able to verify the metadata of the minted NFT through the Display View", func(t *testing.T) {
t.Run("Should be able to verify the metadata of the minted NFT", func(t *testing.T) {

// Run a script to get the Display view for the specified NFT ID
script := templates.GenerateGetNFTMetadataScript(nftAddress, exampleNFTAddress, metadataAddress)
Expand Down Expand Up @@ -193,6 +193,133 @@ func TestGetNFTMetadata(t *testing.T) {
})
}

func TestGetNFTView(t *testing.T) {
b, accountKeys := newTestSetup(t)

// Create new keys for the NFT contract account
// and deploy all the NFT contracts
exampleNFTAccountKey, exampleNFTSigner := accountKeys.NewWithSigner()
nftAddress, metadataAddress, exampleNFTAddress := deployNFTContracts(t, b, exampleNFTAccountKey)

// Mint a single NFT with standard royalty cuts and metadata
mintExampleNFT(t, b,
accountKeys,
nftAddress, metadataAddress, exampleNFTAddress,
exampleNFTAccountKey,
exampleNFTSigner)

t.Run("Should be able to verify the nft metadata view of the minted NFT", func(t *testing.T) {

// Run a script to get the Display view for the specified NFT ID
script := templates.GenerateGetNFTViewScript(nftAddress, exampleNFTAddress, metadataAddress)
result := executeScriptAndCheck(
t, b,
script,
[][]byte{
jsoncdc.MustEncode(cadence.NewAddress(exampleNFTAddress)),
jsoncdc.MustEncode(cadence.NewUInt64(0)),
},
)

// Expected metadata
const (
name = "Example NFT 0"
description = "This is an example NFT"
thumbnail = "example.jpeg"
externalURL = "https://example-nft.onflow.org/0"
)

nftResult := result.(cadence.Struct)

assert.Equal(t, cadence.NewUInt64(0), nftResult.Fields[0])
assert.Equal(t, cadence.String(name), nftResult.Fields[2])
assert.Equal(t, cadence.String(name), nftResult.Fields[2])
assert.Equal(t, cadence.String(description), nftResult.Fields[3])
assert.Equal(t, cadence.String(thumbnail), nftResult.Fields[4])

royalties := toJson(t, nftResult.Fields[5])
// Declared an empty interface of type Array
var results map[string]interface{}

// Unmarshal or Decode the JSON to the interface.
json.Unmarshal([]byte(royalties), &results)

// Verify external URL view result is as expected
assert.Equal(t, cadence.String(externalURL), nftResult.Fields[6])

// Verify NFTCollectionData results are as expected
const (
pathName = "exampleNFTCollection"
collectionType = "A.f3fcd2c1a78f5eee.ExampleNFT.Collection"
collectionPublicType = "A.f3fcd2c1a78f5eee.ExampleNFT.ExampleNFTCollectionPublic"
nftCollectionPublicType = "A.01cf0e2f2f715450.NonFungibleToken.CollectionPublic"
nftReceiverType = "A.01cf0e2f2f715450.NonFungibleToken.Receiver"
resolverCollectionType = "A.179b6b1cb6755e31.MetadataViews.ResolverCollection"
providerType = "A.01cf0e2f2f715450.NonFungibleToken.Provider"
)
assert.Equal(t, cadence.Path{Domain: "public", Identifier: pathName}, nftResult.Fields[7])
assert.Equal(t, cadence.Path{Domain: "storage", Identifier: pathName}, nftResult.Fields[8])
assert.Equal(t, cadence.Path{Domain: "private", Identifier: pathName}, nftResult.Fields[9])
assert.Equal(t, cadence.String(fmt.Sprintf("&%s{%s}", collectionType, collectionPublicType)), nftResult.Fields[10])
assert.Equal(t, cadence.String(fmt.Sprintf("&%s{%s,%s,%s,%s}", collectionType, collectionPublicType, nftCollectionPublicType, nftReceiverType, resolverCollectionType)), nftResult.Fields[11])
assert.Equal(t, cadence.String(fmt.Sprintf("&%s{%s,%s,%s,%s}", collectionType, collectionPublicType, nftCollectionPublicType, providerType, resolverCollectionType)), nftResult.Fields[12])

// Verify NFTCollectionDisplay results are as expected
const (
collectionName = "The Example Collection"
collectionDescription = "This collection is used as an example to help you develop your next Flow NFT."
collectionImage = "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
collectionExternalURL = "https://example-nft.onflow.org"
)
assert.Equal(t, cadence.String(collectionName), nftResult.Fields[13])
assert.Equal(t, cadence.String(collectionDescription), nftResult.Fields[14])
assert.Equal(t, cadence.String(collectionExternalURL), nftResult.Fields[15])
assert.Equal(t, cadence.String(collectionImage), nftResult.Fields[16])
assert.Equal(t, cadence.String(collectionImage), nftResult.Fields[17])

minterName, _ := cadence.NewString("minter")

traitsView := nftResult.Fields[19].(cadence.Struct)
traits := traitsView.Fields[0].(cadence.Array)

mintTrait := traits.Values[0].(cadence.Struct)
assert.Equal(t, minterName, mintTrait.Fields[0])
assert.Equal(t, fmt.Sprintf("0x%s", exampleNFTAddress.String()), mintTrait.Fields[1].String())
assert.Equal(t, cadence.NewOptional(nil), mintTrait.Fields[2])
assert.Equal(t, cadence.NewOptional(nil), mintTrait.Fields[3])

blockNumberName, _ := cadence.NewString("mintedBlock")
blockNumberTrait := traits.Values[1].(cadence.Struct)
assert.Equal(t, blockNumberName, blockNumberTrait.Fields[0])
assert.Equal(t, cadence.NewUInt64(13), blockNumberTrait.Fields[1])
assert.Equal(t, cadence.NewOptional(nil), blockNumberTrait.Fields[2])
assert.Equal(t, cadence.NewOptional(nil), blockNumberTrait.Fields[3])

mintedTimeName, _ := cadence.NewString("mintedTime")
mintedTimeDisplayType, _ := cadence.NewString("Date")
mintedTimeTrait := traits.Values[2].(cadence.Struct)
assert.Equal(t, mintedTimeName, mintedTimeTrait.Fields[0])
assert.Equal(t, cadence.NewOptional(mintedTimeDisplayType), mintedTimeTrait.Fields[2])

fooName, _ := cadence.NewString("foo")
fooValue, _ := cadence.NewString("bar")
fooTrait := traits.Values[3].(cadence.Struct)
fooRarityOptional := fooTrait.Fields[3].(cadence.Optional)
fooRarity := fooRarityOptional.Value.(cadence.Struct)
rarityDescription, _ := cadence.NewString("Common")
assert.Equal(t, fooName, fooTrait.Fields[0])
assert.Equal(t, cadence.NewOptional(fooValue), fooTrait.Fields[1])
fooRarityScore := fooRarity.Fields[0].(cadence.Optional).Value
score, _ := cadence.NewUFix64("10.0")
assert.Equal(t, fooRarityScore, score)
fooRarityMax := fooRarity.Fields[1].(cadence.Optional).Value
max, _ := cadence.NewUFix64("100.0")
assert.Equal(t, max, fooRarityMax)
assert.Equal(t, fooRarity.Fields[2], cadence.NewOptional(rarityDescription))

})
}

func TestSetupCollectionFromNFTReference(t *testing.T) {
b, accountKeys := newTestSetup(t)

Expand Down
Loading