From 19a9aae07d6dfa32d9453e16991c098445b8d63b Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 00:20:10 -0700 Subject: [PATCH 1/6] Add BlindNFT metadata view --- cadence/metadata-views/FreshmintMetadataViews.cdc | 9 +++++++++ src/lib/config.ts | 1 + src/lib/generators/FreshmintMetadataViewsGenerator.ts | 7 +++++++ src/lib/index.ts | 1 + 4 files changed, 18 insertions(+) create mode 100644 cadence/metadata-views/FreshmintMetadataViews.cdc create mode 100644 src/lib/generators/FreshmintMetadataViewsGenerator.ts diff --git a/cadence/metadata-views/FreshmintMetadataViews.cdc b/cadence/metadata-views/FreshmintMetadataViews.cdc new file mode 100644 index 00000000..965e248d --- /dev/null +++ b/cadence/metadata-views/FreshmintMetadataViews.cdc @@ -0,0 +1,9 @@ +pub contract FreshmintMetadataViews { + pub struct BlindNFT { + pub let metadataHash: [UInt8] + + init(metadataHash: [UInt8]) { + self.metadataHash = metadataHash + } + } +} diff --git a/src/lib/config.ts b/src/lib/config.ts index 0b3caf7e..8c97d121 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -19,6 +19,7 @@ export namespace FreshmintConfig { NonFungibleToken: '0xf8d6e0586b0a20c7', FlowToken: '0x0ae53cb6e3f42a79', MetadataViews: '0xf8d6e0586b0a20c7', + FreshmintMetadataViews: '0xf8d6e0586b0a20c7', NFTClaimSale: '0xf8d6e0586b0a20c7', }, }; diff --git a/src/lib/generators/FreshmintMetadataViewsGenerator.ts b/src/lib/generators/FreshmintMetadataViewsGenerator.ts new file mode 100644 index 00000000..c780daa6 --- /dev/null +++ b/src/lib/generators/FreshmintMetadataViewsGenerator.ts @@ -0,0 +1,7 @@ +import TemplateGenerator from './TemplateGenerator'; + +export class FreshmintMetadataViewsGenerator extends TemplateGenerator { + static contract(): string { + return this.generate('../../../cadence/metadata-views/FreshmintMetadataViews.cdc', {}); + } +} diff --git a/src/lib/index.ts b/src/lib/index.ts index 716fe3e7..d7fa4e46 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -20,6 +20,7 @@ export { ClaimSaleContract } from './contracts/ClaimSaleContract'; export { ClaimSaleGenerator } from './generators/ClaimSaleGenerator'; export { NFTAirDropGenerator } from './generators/NFTAirDropGenerator'; +export { FreshmintMetadataViewsGenerator } from './generators/FreshmintMetadataViewsGenerator'; export { OnChainCollection } from './collections/OnChainCollection'; export { OnChainBlindCollection } from './collections/OnChainBlindCollection'; From 6304b6c5f03bc4728eb06bd9f820ab4551b59591 Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 00:20:29 -0700 Subject: [PATCH 2/6] Update blind NFT contracts to use blind metadata view --- .../BlindEditionNFT.template.cdc | 35 +++++++++++++------ cadence/blind-nft/BlindNFT.template.cdc | 34 ++++++++++++------ 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/cadence/blind-edition-nft/BlindEditionNFT.template.cdc b/cadence/blind-edition-nft/BlindEditionNFT.template.cdc index 4dac8838..f83247fb 100644 --- a/cadence/blind-edition-nft/BlindEditionNFT.template.cdc +++ b/cadence/blind-edition-nft/BlindEditionNFT.template.cdc @@ -1,6 +1,7 @@ import NonFungibleToken from {{{ imports.NonFungibleToken }}} import MetadataViews from {{{ imports.MetadataViews }}} import FungibleToken from {{{ imports.FungibleToken }}} +import FreshmintMetadataViews from {{{ imports.FreshmintMetadataViews }}} pub contract {{ contractName }}: NonFungibleToken { @@ -134,15 +135,22 @@ pub contract {{ contractName }}: NonFungibleToken { } pub fun getViews(): [Type] { - {{#if views }} + if self.getEdition() != nil { + {{#if views }} + return [ + {{#each views}} + {{{ this.cadenceTypeString }}}{{#unless @last}},{{/unless}} + {{/each}} + ] + {{ else }} + return [] + {{/if}} + } + return [ - {{#each views}} - {{{ this.cadenceTypeString }}}{{#unless @last}},{{/unless}} - {{/each}} + Type(), + Type() ] - {{ else }} - return [] - {{/if}} } pub fun resolveView(_ view: Type): AnyStruct? { @@ -158,7 +166,15 @@ pub contract {{ contractName }}: NonFungibleToken { {{/with}} {{/each}} } + + return nil + } + {{ else }} + + if self.getEdition() != nil { + return [] } + {{/if}} switch view { case Type(): @@ -170,12 +186,11 @@ pub contract {{ contractName }}: NonFungibleToken { path: nil ) ) + case Type(): + return FreshmintMetadataViews.BlindNFT(metadataHash: self.editionHash) } return nil - {{ else }} - return nil - {{/if}} } destroy() { diff --git a/cadence/blind-nft/BlindNFT.template.cdc b/cadence/blind-nft/BlindNFT.template.cdc index c893fd16..d3cc55be 100644 --- a/cadence/blind-nft/BlindNFT.template.cdc +++ b/cadence/blind-nft/BlindNFT.template.cdc @@ -1,6 +1,7 @@ import NonFungibleToken from {{{ imports.NonFungibleToken }}} import MetadataViews from {{{ imports.MetadataViews }}} import FungibleToken from {{{ imports.FungibleToken }}} +import FreshmintMetadataViews from {{{ imports.FreshmintMetadataViews }}} pub contract {{ contractName }}: NonFungibleToken { @@ -102,15 +103,22 @@ pub contract {{ contractName }}: NonFungibleToken { } pub fun getViews(): [Type] { - {{#if views }} + if self.getMetadata() != nil { + {{#if views }} + return [ + {{#each views}} + {{{ this.cadenceTypeString }}}{{#unless @last}},{{/unless}} + {{/each}} + ] + {{ else }} + return [] + {{/if}} + } + return [ - {{#each views}} - {{{ this.cadenceTypeString }}}{{#unless @last}},{{/unless}} - {{/each}} + Type(), + Type() ] - {{ else }} - return [] - {{/if}} } pub fun resolveView(_ view: Type): AnyStruct? { @@ -124,7 +132,14 @@ pub contract {{ contractName }}: NonFungibleToken { {{/with}} {{/each}} } + + return nil + } + {{ else }} + if self.getMetadata() != nil { + return [] } + {{/if}} switch view { case Type(): @@ -136,12 +151,11 @@ pub contract {{ contractName }}: NonFungibleToken { path: nil ) ) + case Type(): + return FreshmintMetadataViews.BlindNFT(metadataHash: self.metadataHash) } return nil - {{ else }} - return nil - {{/if}} } destroy() { From 3f36375e03e9cd7bfb8c98b22404f093ab5cb484 Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 00:20:46 -0700 Subject: [PATCH 3/6] Add get_nft.cdc script to core lib --- cadence/common-nft/scripts/get_nft.cdc | 45 ++++++++++++++++++++++++ src/lib/generators/CommonNFTGenerator.ts | 16 +++++++++ src/lib/index.ts | 1 + 3 files changed, 62 insertions(+) create mode 100644 cadence/common-nft/scripts/get_nft.cdc create mode 100644 src/lib/generators/CommonNFTGenerator.ts diff --git a/cadence/common-nft/scripts/get_nft.cdc b/cadence/common-nft/scripts/get_nft.cdc new file mode 100644 index 00000000..54092d5d --- /dev/null +++ b/cadence/common-nft/scripts/get_nft.cdc @@ -0,0 +1,45 @@ +import {{ contractName }} from {{{ contractAddress }}} +import NonFungibleToken from {{{ imports.NonFungibleToken }}} +import MetadataViews from {{{ imports.MetadataViews }}} +import FreshmintMetadataViews from {{{ imports.FreshmintMetadataViews }}} + +pub struct NFT { + pub let id: UInt64 + + pub let display: MetadataViews.Display + pub let metadataHash: String? + + init( + id: UInt64, + display: MetadataViews.Display, + metadataHash: String? + ) { + self.id = id + self.display = display + self.metadataHash = metadataHash + } +} + +pub fun main(address: Address, id: UInt64): NFT? { + if let col = getAccount(address).getCapability<&{{ contractName }}.Collection{NonFungibleToken.CollectionPublic, {{ contractName }}.{{ contractName }}CollectionPublic}>({{ contractName }}.CollectionPublicPath).borrow() { + if let nft = col.borrow{{ contractName }}(id: id) { + + let display = nft.resolveView(Type())! as! MetadataViews.Display + + var metadataHash: String? = nil + + if let blindNFTView = nft.resolveView(Type()) { + let blindNFT = blindNFTView as! FreshmintMetadataViews.BlindNFT + metadataHash = String.encodeHex(blindNFT.metadataHash) + } + + return NFT( + id: id, + display: display, + metadataHash: metadataHash + ) + } + } + + return nil +} diff --git a/src/lib/generators/CommonNFTGenerator.ts b/src/lib/generators/CommonNFTGenerator.ts new file mode 100644 index 00000000..39a7045f --- /dev/null +++ b/src/lib/generators/CommonNFTGenerator.ts @@ -0,0 +1,16 @@ +import { ContractImports } from '../config'; +import TemplateGenerator from './TemplateGenerator'; + +export class CommonNFTGenerator extends TemplateGenerator { + static getNFT({ + imports, + contractName, + contractAddress, + }: { + imports: ContractImports; + contractName: string; + contractAddress: string; + }): string { + return this.generate('../../../cadence/common-nft/scripts/get_nft.cdc', { imports, contractName, contractAddress }); + } +} diff --git a/src/lib/index.ts b/src/lib/index.ts index d7fa4e46..00ccc079 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -20,6 +20,7 @@ export { ClaimSaleContract } from './contracts/ClaimSaleContract'; export { ClaimSaleGenerator } from './generators/ClaimSaleGenerator'; export { NFTAirDropGenerator } from './generators/NFTAirDropGenerator'; +export { CommonNFTGenerator } from './generators/CommonNFTGenerator'; export { FreshmintMetadataViewsGenerator } from './generators/FreshmintMetadataViewsGenerator'; export { OnChainCollection } from './collections/OnChainCollection'; From 39b4f8bae5be774a5d6353c50e1ded85ad3bbe37 Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 00:21:26 -0700 Subject: [PATCH 4/6] Include FreshmintMetadataViews, NFTClaimSale, get_nft in generate project --- src/cli/generateProject.ts | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/cli/generateProject.ts b/src/cli/generateProject.ts index 260015bb..4061cf98 100644 --- a/src/cli/generateProject.ts +++ b/src/cli/generateProject.ts @@ -1,7 +1,15 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as Handlebars from 'handlebars'; -import { ContractImports, StandardNFTGenerator, EditionNFTGenerator, NFTAirDropGenerator } from '../lib'; +import { + ContractImports, + StandardNFTGenerator, + EditionNFTGenerator, + NFTAirDropGenerator, + FreshmintMetadataViewsGenerator, + CommonNFTGenerator, + ClaimSaleGenerator, +} from '../lib'; import { ContractConfig, ContractType } from './config'; export async function generateProject(dir: string, contract: ContractConfig, nftDataPath: string) { @@ -20,6 +28,7 @@ export async function generateProjectCadence(dir: string, contract: ContractConf const imports = { NonFungibleToken: `"./NonFungibleToken.cdc"`, MetadataViews: `"./MetadataViews.cdc"`, + FreshmintMetadataViews: `"./FreshmintMetadataViews.cdc"`, FungibleToken: `"./FungibleToken.cdc"`, FlowToken: `"./FlowToken.cdc"`, NFTAirDrop: `"./NFTAirDrop.cdc"`, @@ -35,8 +44,12 @@ export async function generateProjectCadence(dir: string, contract: ContractConf } await writeFile(path.resolve(dir, `cadence/contracts/NFTAirDrop.cdc`), NFTAirDropGenerator.contract({ imports })); + await writeFile(path.resolve(dir, `cadence/contracts/NFTClaimSale.cdc`), ClaimSaleGenerator.contract({ imports })); - await createGetNFTScript(dir, contract.name); + await writeFile( + path.resolve(dir, `cadence/contracts/FreshmintMetadataViews.cdc`), + FreshmintMetadataViewsGenerator.contract(), + ); } async function generateStandardProject( @@ -62,6 +75,8 @@ async function generateStandardProject( // Find a better solution. NonFungibleToken: `"../contracts/NonFungibleToken.cdc"`, NFTAirDrop: `"../contracts/NFTAirDrop.cdc"`, + MetadataViews: `"../contracts/MetadataViews.cdc"`, + FreshmintMetadataViews: `"../contracts/FreshmintMetadataViews.cdc"`, }; const mintTransaction = StandardNFTGenerator.mint({ @@ -85,6 +100,11 @@ async function generateStandardProject( if (includeCSVFile) { await createNFTsCSVFile(dir, contract.name, { fields: contract.schema.fields }); } + + await writeFile( + path.resolve(dir, `cadence/scripts/get_nft.cdc`), + CommonNFTGenerator.getNFT({ imports: adjustedImports, contractName: contract.name, contractAddress }), + ); } async function generateEditionProject( @@ -110,6 +130,8 @@ async function generateEditionProject( // Find a better solution. NonFungibleToken: `"../contracts/NonFungibleToken.cdc"`, NFTAirDrop: `"../contracts/NFTAirDrop.cdc"`, + MetadataViews: `"../contracts/MetadataViews.cdc"`, + FreshmintMetadataViews: `"../contracts/FreshmintMetadataViews.cdc"`, }; const createEditionsTransaction = EditionNFTGenerator.createEditions({ @@ -140,6 +162,11 @@ async function generateEditionProject( if (includeCSVFile) { await createEditionsCSVFile(dir, contract.name, { fields: contract.schema.fields }); } + + await writeFile( + path.resolve(dir, `cadence/scripts/get_nft.cdc`), + CommonNFTGenerator.getNFT({ imports: adjustedImports, contractName: contract.name, contractAddress }), + ); } async function createScaffold(dir: string) { @@ -170,8 +197,6 @@ async function createScaffold(dir: string) { await fs.copy(path.resolve(__dirname, 'templates/gitignore'), path.resolve(dir, '.gitignore')); } -const createGetNFTScript = template('templates/cadence/scripts/get_nft.cdc', 'cadence/scripts/get_nft.cdc'); - const createNFTsCSVFile = template('templates/nfts.csv', 'nfts.csv'); const createEditionsCSVFile = template('templates/editions.csv', 'editions.csv'); From 232c8a70272a9126e92687d4887644975a861e8a Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 10:30:39 -0700 Subject: [PATCH 5/6] Add comment to BlindNFT view --- cadence/metadata-views/FreshmintMetadataViews.cdc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cadence/metadata-views/FreshmintMetadataViews.cdc b/cadence/metadata-views/FreshmintMetadataViews.cdc index 965e248d..bca31dde 100644 --- a/cadence/metadata-views/FreshmintMetadataViews.cdc +++ b/cadence/metadata-views/FreshmintMetadataViews.cdc @@ -1,4 +1,8 @@ pub contract FreshmintMetadataViews { + + // BlindNFT returns a representation of + // a hidden or "blind" NFT, which at this point + // is a secure hash of the NFT's metadata values. pub struct BlindNFT { pub let metadataHash: [UInt8] From 48405a78da1502b888b9cbc7050c517f41328507 Mon Sep 17 00:00:00 2001 From: Peter Siemens Date: Mon, 29 Aug 2022 10:37:35 -0700 Subject: [PATCH 6/6] Add/update testnet contract addresses --- src/lib/config.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/config.ts b/src/lib/config.ts index 8c97d121..43168a4c 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -21,6 +21,7 @@ export namespace FreshmintConfig { MetadataViews: '0xf8d6e0586b0a20c7', FreshmintMetadataViews: '0xf8d6e0586b0a20c7', NFTClaimSale: '0xf8d6e0586b0a20c7', + NFTAirDrop: '0xf8d6e0586b0a20c7' }, }; @@ -29,7 +30,9 @@ export namespace FreshmintConfig { FungibleToken: '0x9a0766d93b6608b7', NonFungibleToken: '0x631e88ae7f1d7c20', MetadataViews: '0x631e88ae7f1d7c20', - NFTClaimSale: '0xc7cfd3d1b4951113', + FreshmintMetadataViews: '0x3c67d33388b03a69', + NFTClaimSale: '0x3c67d33388b03a69', + NFTAirDrop: '0x3c67d33388b03a69' }, };