From 404a0ec6506f7c870bcb376139a586163505a46a Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:28:57 -0600 Subject: [PATCH 1/7] remove previewnet from flow.json --- flow.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/flow.json b/flow.json index f39cf1d0..65384829 100644 --- a/flow.json +++ b/flow.json @@ -264,7 +264,6 @@ "aliases": { "emulator": "f8d6e0586b0a20c7", "mainnet": "e467b9dd11fa00df", - "previewnet": "b6763b4399a888c8", "testnet": "8c5303eaa26202d6" } }, @@ -274,7 +273,6 @@ "aliases": { "emulator": "f8d6e0586b0a20c7", "mainnet": "e467b9dd11fa00df", - "previewnet": "b6763b4399a888c8", "testnet": "8c5303eaa26202d6" } }, @@ -284,7 +282,6 @@ "aliases": { "emulator": "0ae53cb6e3f42a79", "mainnet": "1654653399040a61", - "previewnet": "4445e7ad11568276", "testnet": "7e60df042a9c0868" } }, @@ -294,7 +291,6 @@ "aliases": { "emulator": "ee82856bf20e2aa6", "mainnet": "f233dcee88fe0abe", - "previewnet": "a0225e7000ac82a9", "testnet": "9a0766d93b6608b7" } }, @@ -304,7 +300,6 @@ "aliases": { "emulator": "ee82856bf20e2aa6", "mainnet": "f233dcee88fe0abe", - "previewnet": "a0225e7000ac82a9", "testnet": "9a0766d93b6608b7" } }, @@ -314,7 +309,6 @@ "aliases": { "emulator": "f8d6e0586b0a20c7", "mainnet": "1d7e57aa55817448", - "previewnet": "b6763b4399a888c8", "testnet": "631e88ae7f1d7c20" } }, @@ -324,7 +318,6 @@ "aliases": { "emulator": "f8d6e0586b0a20c7", "mainnet": "1d7e57aa55817448", - "previewnet": "b6763b4399a888c8", "testnet": "631e88ae7f1d7c20" } }, @@ -334,7 +327,6 @@ "aliases": { "emulator": "f8d6e0586b0a20c7", "mainnet": "1d7e57aa55817448", - "previewnet": "b6763b4399a888c8", "testnet": "631e88ae7f1d7c20" } } From 348012239adec69b42d78cc09b4c6a438074274b Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:30:14 -0600 Subject: [PATCH 2/7] optimize SerializeMetadata --- cadence/contracts/utils/SerializeMetadata.cdc | 66 ++++++++++--------- cadence/tests/serialize_metadata_tests.cdc | 1 - 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/cadence/contracts/utils/SerializeMetadata.cdc b/cadence/contracts/utils/SerializeMetadata.cdc index 7a93695b..3f0a4d8d 100644 --- a/cadence/contracts/utils/SerializeMetadata.cdc +++ b/cadence/contracts/utils/SerializeMetadata.cdc @@ -42,20 +42,16 @@ access(all) contract SerializeMetadata { return "" } // Init the data format prefix & concatenate the serialized display & attributes - var serializedMetadata = "data:application/json;utf8,{" + let parts: [String] = ["data:application/json;utf8,{"] if display != nil { - serializedMetadata = serializedMetadata.concat(display!) + parts.appendAll([display!, ", "]) // Include display if present & separate with a comma } - if display != nil && attributes != nil { - serializedMetadata = serializedMetadata.concat(", ") - } - if attributes != nil { - serializedMetadata = serializedMetadata.concat(attributes) - } - return serializedMetadata.concat("}") + parts.appendAll([attributes, "}"]) // Include attributes & close the JSON object + + return String.join(parts, separator: "") } - /// Serializes the display & collection display views of a given NFT as a JSON compatible string. If nftDisplay is + /// Serializes the display & collection display views of a given NFT as a JSON compatible string. If nftDisplay is /// present, the value is returned as token-level metadata. If nftDisplay is nil and collectionDisplay is present, /// the value is returned as contract-level metadata. If both values are nil, nil is returned. /// @@ -80,30 +76,34 @@ access(all) contract SerializeMetadata { let externalURL = "\"external_url\": " let externalLink = "\"external_link\": " var serializedResult = "" + let parts: [String] = [] // Append results from the token-level Display view to the serialized JSON compatible string if nftDisplay != nil { - serializedResult = serializedResult - .concat(name).concat(Serialize.tryToJSONString(nftDisplay!.name)!).concat(", ") - .concat(description).concat(Serialize.tryToJSONString(nftDisplay!.description)!).concat(", ") - .concat(image).concat(Serialize.tryToJSONString(nftDisplay!.thumbnail.uri())!) - // Append the `externa_url` value from NFTCollectionDisplay view if present + parts.appendAll([ + name, Serialize.tryToJSONString(nftDisplay!.name)!, ", ", + description, Serialize.tryToJSONString(nftDisplay!.description)!, ", ", + image, Serialize.tryToJSONString(nftDisplay!.thumbnail.uri())! + ]) + // Append the `external_url` value from NFTCollectionDisplay view if present if collectionDisplay != nil { - return serializedResult.concat(", ") - .concat(externalURL).concat(Serialize.tryToJSONString(collectionDisplay!.externalURL.url)!) + parts.appendAll([", ", externalURL, Serialize.tryToJSONString(collectionDisplay!.externalURL.url)!]) + return String.join(parts, separator: "") } } if collectionDisplay == nil { - return serializedResult + return String.join(parts, separator: "") } // Without token-level view, serialize as contract-level metadata - return serializedResult - .concat(name).concat(Serialize.tryToJSONString(collectionDisplay!.name)!).concat(", ") - .concat(description).concat(Serialize.tryToJSONString(collectionDisplay!.description)!).concat(", ") - .concat(image).concat(Serialize.tryToJSONString(collectionDisplay!.squareImage.file.uri())!).concat(", ") - .concat(externalLink).concat(Serialize.tryToJSONString(collectionDisplay!.externalURL.url)!) + parts.appendAll([ + name, Serialize.tryToJSONString(collectionDisplay!.name)!, ", ", + description, Serialize.tryToJSONString(collectionDisplay!.description)!, ", ", + image, Serialize.tryToJSONString(collectionDisplay!.squareImage.file.uri())!, ", ", + externalLink, Serialize.tryToJSONString(collectionDisplay!.externalURL.url)! + ]) + return String.join(parts, separator: "") } /// Serializes given Traits view as a JSON compatible string. If a given Trait is not serializable, it is skipped @@ -124,7 +124,7 @@ access(all) contract SerializeMetadata { if value == nil { // Remove trailing comma if last trait is not serializable if i == traitsLength - 1 && serializedResult[serializedResult.length - 1] == "," { - serializedResult = serializedResult.slice(from: 0, upTo: serializedResult.length - 1) + serializedResult = serializedResult.slice(from: 0, upTo: serializedResult.length - 1) } continue } @@ -143,10 +143,10 @@ access(all) contract SerializeMetadata { return serializedResult.concat("]") } - /// Serializes the FTDisplay view of a given fungible token as a JSON compatible data URL. The value is returned as + /// Serializes the FTDisplay view of a given fungible token as a JSON compatible data URL. The value is returned as /// contract-level metadata. /// - /// @param ftDisplay: The tokens's FTDisplay view from which values `name`, `symbol`, `description`, and + /// @param ftDisplay: The tokens's FTDisplay view from which values `name`, `symbol`, `description`, and /// `externaURL` are serialized /// /// @returns: A JSON compatible data URL string containing the serialized view as: @@ -162,13 +162,15 @@ access(all) contract SerializeMetadata { let symbol = "\"symbol\": " let description = "\"description\": " let externalLink = "\"external_link\": " + let parts: [String] = ["data:application/json;utf8,{"] - return "data:application/json;utf8,{" - .concat(name).concat(Serialize.tryToJSONString(ftDisplay.name)!).concat(", ") - .concat(symbol).concat(Serialize.tryToJSONString(ftDisplay.symbol)!).concat(", ") - .concat(description).concat(Serialize.tryToJSONString(ftDisplay.description)!).concat(", ") - .concat(externalLink).concat(Serialize.tryToJSONString(ftDisplay.externalURL.url)!) - .concat("}") + parts.appendAll([ + name, Serialize.tryToJSONString(ftDisplay.name)!, ", ", + symbol, Serialize.tryToJSONString(ftDisplay.symbol)!, ", ", + description, Serialize.tryToJSONString(ftDisplay.description)!, ", ", + externalLink, Serialize.tryToJSONString(ftDisplay.externalURL.url)! + ]) + return String.join(parts, separator: "") } /// Derives a symbol for use as an ERC20 or ERC721 symbol from a given string, presumably a Cadence contract name. diff --git a/cadence/tests/serialize_metadata_tests.cdc b/cadence/tests/serialize_metadata_tests.cdc index 40498d5c..16e0a9c5 100644 --- a/cadence/tests/serialize_metadata_tests.cdc +++ b/cadence/tests/serialize_metadata_tests.cdc @@ -74,7 +74,6 @@ fun testSerializeNFTSucceeds() { Test.expect(serializeMetadataResult, Test.beSucceeded()) let serializedMetadata = serializeMetadataResult.returnValue! as! String - Test.assertEqual(true, serializedMetadata == expectedPrefix.concat(altSuffix1) || serializedMetadata == expectedPrefix.concat(altSuffix2)) } From 7f552298b92dd67d1a3a06628e8d0f40e88aa88a Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:30:31 -0600 Subject: [PATCH 3/7] optimize Serialize --- cadence/contracts/utils/Serialize.cdc | 84 +++++++++++---------------- cadence/tests/serialize_tests.cdc | 1 + 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/cadence/contracts/utils/Serialize.cdc b/cadence/contracts/utils/Serialize.cdc index 0e2dc9ef..6c83f2ce 100644 --- a/cadence/contracts/utils/Serialize.cdc +++ b/cadence/contracts/utils/Serialize.cdc @@ -27,59 +27,59 @@ contract Serialize { case Type(): return "\"nil\"" case Type(): - return "\"".concat(value as! String).concat("\"") + return String.join(["\"", value as! String, "\"" ], separator: "") case Type(): - return "\"".concat(value as? String ?? "nil").concat("\"") + return String.join(["\"", value as? String ?? "nil", "\"" ], separator: "") case Type(): - return "\"".concat((value as! Character).toString()).concat("\"") + return String.join(["\"", (value as! Character).toString(), "\"" ], separator: "") case Type(): - return "\"".concat(value as! Bool ? "true" : "false").concat("\"") + return String.join(["\"", value as! Bool ? "true" : "false", "\"" ], separator: "") case Type
(): - return "\"".concat((value as! Address).toString()).concat("\"") + return String.join(["\"", (value as! Address).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as? Address)?.toString() ?? "nil").concat("\"") + return String.join(["\"", (value as? Address)?.toString() ?? "nil", "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int8).toString()).concat("\"") + return String.join(["\"", (value as! Int8).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int16).toString()).concat("\"") + return String.join(["\"", (value as! Int16).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int32).toString()).concat("\"") + return String.join(["\"", (value as! Int32).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int64).toString()).concat("\"") + return String.join(["\"", (value as! Int64).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int128).toString()).concat("\"") + return String.join(["\"", (value as! Int128).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int256).toString()).concat("\"") + return String.join(["\"", (value as! Int256).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Int).toString()).concat("\"") + return String.join(["\"", (value as! Int).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt8).toString()).concat("\"") + return String.join(["\"", (value as! UInt8).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt16).toString()).concat("\"") + return String.join(["\"", (value as! UInt16).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt32).toString()).concat("\"") + return String.join(["\"", (value as! UInt32).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt64).toString()).concat("\"") + return String.join(["\"", (value as! UInt64).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt128).toString()).concat("\"") + return String.join(["\"", (value as! UInt128).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt256).toString()).concat("\"") + return String.join(["\"", (value as! UInt256).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UInt).toString()).concat("\"") + return String.join(["\"", (value as! UInt).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word8).toString()).concat("\"") + return String.join(["\"", (value as! Word8).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word16).toString()).concat("\"") + return String.join(["\"", (value as! Word16).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word32).toString()).concat("\"") + return String.join(["\"", (value as! Word32).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word64).toString()).concat("\"") + return String.join(["\"", (value as! Word64).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word128).toString()).concat("\"") + return String.join(["\"", (value as! Word128).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! Word256).toString()).concat("\"") + return String.join(["\"", (value as! Word256).toString(), "\"" ], separator: "") case Type(): - return "\"".concat((value as! UFix64).toString()).concat("\"") + return String.join(["\"", (value as! UFix64).toString(), "\"" ], separator: "") default: return nil } @@ -89,24 +89,15 @@ contract Serialize { /// access(all) fun arrayToJSONString(_ arr: [AnyStruct]): String? { - var serializedArr = "[" - let arrLength = arr.length + let parts: [String]= [] for i, element in arr { let serializedElement = self.tryToJSONString(element) if serializedElement == nil { - if i == arrLength - 1 && serializedArr.length > 1 && serializedArr[serializedArr.length - 2] == "," { - // Remove trailing comma as this element could not be serialized - serializedArr = serializedArr.slice(from: 0, upTo: serializedArr.length - 2) - } continue } - serializedArr = serializedArr.concat(serializedElement!) - // Add a comma if there are more elements to serialize - if i < arr.length - 1 { - serializedArr = serializedArr.concat(", ") - } + parts.append(serializedElement!) } - return serializedArr.concat("]") + return "[".concat(String.join(parts, separator: ", ")).concat("]") } /// Returns a serialized representation of the given String-indexed mapping or nil if the value is not serializable. @@ -120,22 +111,15 @@ contract Serialize { dict.remove(key: k) } } - var serializedDict = "{" - let dictLength = dict.length + let parts: [String] = [] for i, key in dict.keys { let serializedValue = self.tryToJSONString(dict[key]!) if serializedValue == nil { - if i == dictLength - 1 && serializedDict.length > 1 && serializedDict[serializedDict.length - 2] == "," { - // Remove trailing comma as this element could not be serialized - serializedDict = serializedDict.slice(from: 0, upTo: serializedDict.length - 2) - } continue } - serializedDict = serializedDict.concat(self.tryToJSONString(key)!).concat(": ").concat(serializedValue!) - if i < dict.length - 1 { - serializedDict = serializedDict.concat(", ") - } + let serialializedKeyValue = String.join([self.tryToJSONString(key)!, serializedValue!], separator: ": ") + parts.append(serialializedKeyValue) } - return serializedDict.concat("}") + return "{".concat(String.join(parts, separator: ", ")).concat("}") } } diff --git a/cadence/tests/serialize_tests.cdc b/cadence/tests/serialize_tests.cdc index e472b907..b0c0b5ef 100644 --- a/cadence/tests/serialize_tests.cdc +++ b/cadence/tests/serialize_tests.cdc @@ -239,6 +239,7 @@ fun testDictToJSONStringSucceeds() { var expectedTwo: String = "{\"arr\": [\"127\", \"Hello, World!\"], \"bool\": \"true\"}" var actual: String? = Serialize.dictToJSONString(dict: dict, excludedNames: nil) + log(actual) Test.assertEqual(true, expectedOne == actual! || expectedTwo == actual!) actual = Serialize.tryToJSONString(dict) From 6f9f8624c07b526b1753754c68dd785547ef8443 Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:50:03 -0600 Subject: [PATCH 4/7] fix serializeNFTMetadataAsURI conditional --- cadence/contracts/utils/SerializeMetadata.cdc | 5 +++-- cadence/tests/serialize_tests.cdc | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cadence/contracts/utils/SerializeMetadata.cdc b/cadence/contracts/utils/SerializeMetadata.cdc index 3f0a4d8d..d38c4045 100644 --- a/cadence/contracts/utils/SerializeMetadata.cdc +++ b/cadence/contracts/utils/SerializeMetadata.cdc @@ -31,14 +31,15 @@ access(all) contract SerializeMetadata { // Serialize the display values from the NFT's Display & NFTCollectionDisplay views let nftDisplay = nft.resolveView(Type()) as! MetadataViews.Display? let collectionDisplay = nft.resolveView(Type()) as! MetadataViews.NFTCollectionDisplay? + // Serialize the display & collection display views - nil if both views are nil let display = self.serializeFromDisplays(nftDisplay: nftDisplay, collectionDisplay: collectionDisplay) // Get the Traits view from the NFT, returning early if no traits are found let traits = nft.resolveView(Type()) as! MetadataViews.Traits? let attributes = self.serializeNFTTraitsAsAttributes(traits ?? MetadataViews.Traits([])) - // Return an empty string if nothing is serializable - if display == nil && attributes == nil { + // Return an empty string if all views are nil + if display == nil && traits == nil { return "" } // Init the data format prefix & concatenate the serialized display & attributes diff --git a/cadence/tests/serialize_tests.cdc b/cadence/tests/serialize_tests.cdc index b0c0b5ef..e472b907 100644 --- a/cadence/tests/serialize_tests.cdc +++ b/cadence/tests/serialize_tests.cdc @@ -239,7 +239,6 @@ fun testDictToJSONStringSucceeds() { var expectedTwo: String = "{\"arr\": [\"127\", \"Hello, World!\"], \"bool\": \"true\"}" var actual: String? = Serialize.dictToJSONString(dict: dict, excludedNames: nil) - log(actual) Test.assertEqual(true, expectedOne == actual! || expectedTwo == actual!) actual = Serialize.tryToJSONString(dict) From 56cc52e85af6985debf85f2d07564f7e982525eb Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:18:00 -0600 Subject: [PATCH 5/7] optimize serializeNFTTraitsAsAttributes & add single trait serialization --- cadence/contracts/utils/Serialize.cdc | 4 +- cadence/contracts/utils/SerializeMetadata.cdc | 48 +++++++++++-------- cadence/tests/serialize_metadata_tests.cdc | 5 +- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/cadence/contracts/utils/Serialize.cdc b/cadence/contracts/utils/Serialize.cdc index 6c83f2ce..d8123728 100644 --- a/cadence/contracts/utils/Serialize.cdc +++ b/cadence/contracts/utils/Serialize.cdc @@ -90,7 +90,7 @@ contract Serialize { access(all) fun arrayToJSONString(_ arr: [AnyStruct]): String? { let parts: [String]= [] - for i, element in arr { + for element in arr { let serializedElement = self.tryToJSONString(element) if serializedElement == nil { continue @@ -112,7 +112,7 @@ contract Serialize { } } let parts: [String] = [] - for i, key in dict.keys { + for key in dict.keys { let serializedValue = self.tryToJSONString(dict[key]!) if serializedValue == nil { continue diff --git a/cadence/contracts/utils/SerializeMetadata.cdc b/cadence/contracts/utils/SerializeMetadata.cdc index d38c4045..0f299bec 100644 --- a/cadence/contracts/utils/SerializeMetadata.cdc +++ b/cadence/contracts/utils/SerializeMetadata.cdc @@ -112,36 +112,44 @@ access(all) contract SerializeMetadata { /// /// @param traits: The Traits view to be serialized /// - /// @returns: A JSON compatible string containing the serialized traits as: + /// @returns: A JSON compatible string containing the serialized traits as follows + /// (display_type omitted if trait.displayType == nil): /// `\"attributes\": [{\"trait_type\": \"\", \"display_type\": \"\", \"value\": \"\"}, {...}]` /// access(all) fun serializeNFTTraitsAsAttributes(_ traits: MetadataViews.Traits): String { // Serialize each trait as an attribute, building the serialized JSON compatible string - var serializedResult = "\"attributes\": [" + let parts: [String] = [] let traitsLength = traits.traits.length for i, trait in traits.traits { - let value = Serialize.tryToJSONString(trait.value) - if value == nil { - // Remove trailing comma if last trait is not serializable - if i == traitsLength - 1 && serializedResult[serializedResult.length - 1] == "," { - serializedResult = serializedResult.slice(from: 0, upTo: serializedResult.length - 1) - } + let attribute = self.serializeNFTTraitAsAttribute(trait) + if attribute == nil { continue } - serializedResult = serializedResult.concat("{") - .concat("\"trait_type\": ").concat(Serialize.tryToJSONString(trait.name)!) - if trait.displayType != nil { - serializedResult = serializedResult.concat(", \"display_type\": ") - .concat(Serialize.tryToJSONString(trait.displayType)!) - } - serializedResult = serializedResult.concat(", \"value\": ").concat(value!) - .concat("}") - if i < traits!.traits.length - 1 { - serializedResult = serializedResult.concat(",") - } + parts.append(attribute!) + } + // Join all serialized attributes with a comma separator, wrapping the result in square brackets under the + // `attributes` key + return "\"attributes\": [".concat(String.join(parts, separator: ", ")).concat("]") + } + + /// Serializes a given Trait as an attribute in a JSON compatible format. If the trait's value is not serializable, + /// nil is returned. + /// The format of the serialized trait is as follows (display_type omitted if trait.displayType == nil): + /// `{"trait_type": "", "display_type": "", "value": ""}` + access(all) + fun serializeNFTTraitAsAttribute(_ trait: MetadataViews.Trait): String? { + let value = Serialize.tryToJSONString(trait.value) + if value == nil { + return nil } - return serializedResult.concat("]") + let parts: [String] = ["{"] + parts.appendAll( [ "\"trait_type\": ", Serialize.tryToJSONString(trait.name)! ] ) + if trait.displayType != nil { + parts.appendAll( [ ", \"display_type\": ", Serialize.tryToJSONString(trait.displayType)! ] ) + } + parts.appendAll( [ ", \"value\": ", value! , "}" ] ) + return String.join(parts, separator: "") } /// Serializes the FTDisplay view of a given fungible token as a JSON compatible data URL. The value is returned as diff --git a/cadence/tests/serialize_metadata_tests.cdc b/cadence/tests/serialize_metadata_tests.cdc index 16e0a9c5..f35ddb23 100644 --- a/cadence/tests/serialize_metadata_tests.cdc +++ b/cadence/tests/serialize_metadata_tests.cdc @@ -56,9 +56,10 @@ fun testSerializeNFTSucceeds() { mintedBlockHeight = heightResult.returnValue! as! UInt64 let heightString = mintedBlockHeight.toString() + // Cadence dictionaries are not ordered by insertion order, so we need to check for both possible orderings let expectedPrefix = "data:application/json;utf8,{\"name\": \"ExampleNFT\", \"description\": \"Example NFT Collection\", \"image\": \"https://flow.com/examplenft.jpg\", \"external_url\": \"https://example-nft.onflow.org\", " - let altSuffix1 = "\"attributes\": [{\"trait_type\": \"mintedBlock\", \"value\": \"".concat(heightString).concat("\"},{\"trait_type\": \"foo\", \"value\": \"nil\"}]}") - let altSuffix2 = "\"attributes\": [{\"trait_type\": \"foo\", \"value\": \"nil\"}]}, {\"trait_type\": \"mintedBlock\", \"value\": \"".concat(heightString).concat("\"}") + let altSuffix1 = "\"attributes\": [{\"trait_type\": \"mintedBlock\", \"value\": \"".concat(heightString).concat("\"}, {\"trait_type\": \"foo\", \"value\": \"nil\"}]}") + let altSuffix2 = "\"attributes\": [{\"trait_type\": \"foo\", \"value\": \"nil\"}, {\"trait_type\": \"mintedBlock\", \"value\": \"".concat(heightString).concat("\"}]}") let idsResult = executeScript( "../scripts/nft/get_ids.cdc", From 7898bff3ac6bde05118c529abd4802cb9f034e8b Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:16:28 -0600 Subject: [PATCH 6/7] update attributions --- cadence/contracts/utils/Serialize.cdc | 2 +- cadence/contracts/utils/SerializeMetadata.cdc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cadence/contracts/utils/Serialize.cdc b/cadence/contracts/utils/Serialize.cdc index d8123728..41c9892f 100644 --- a/cadence/contracts/utils/Serialize.cdc +++ b/cadence/contracts/utils/Serialize.cdc @@ -5,7 +5,7 @@ import "NonFungibleToken" /// This contract is a utility for serializing primitive types, arrays, and common metadata mapping formats to JSON /// compatible strings. Also included are interfaces enabling custom serialization for structs and resources. /// -/// Special thanks to @austinkline for the idea and initial implementation. +/// Special thanks to @austinkline for the idea and initial implementation & @bjartek + @bluesign for optimizations. /// access(all) contract Serialize { diff --git a/cadence/contracts/utils/SerializeMetadata.cdc b/cadence/contracts/utils/SerializeMetadata.cdc index 0f299bec..965bf0ba 100644 --- a/cadence/contracts/utils/SerializeMetadata.cdc +++ b/cadence/contracts/utils/SerializeMetadata.cdc @@ -8,6 +8,8 @@ import "Serialize" /// This contract defines methods for serializing NFT metadata as a JSON compatible string, according to the common /// OpenSea metadata format. NFTs and metadata views can be serialized by reference via contract methods. /// +/// Special thanks to @austinkline for the idea and initial implementation & @bjartek + @bluesign for optimizations. +/// access(all) contract SerializeMetadata { /// Serializes the metadata (as a JSON compatible String) for a given NFT according to formats expected by EVM From fae3977a20c438ff0323b7fc40a66be36eaf3393 Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:08:57 -0600 Subject: [PATCH 7/7] remove unused value from SerializeMetadata --- cadence/contracts/utils/SerializeMetadata.cdc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/contracts/utils/SerializeMetadata.cdc b/cadence/contracts/utils/SerializeMetadata.cdc index 965bf0ba..1ceca382 100644 --- a/cadence/contracts/utils/SerializeMetadata.cdc +++ b/cadence/contracts/utils/SerializeMetadata.cdc @@ -123,7 +123,7 @@ access(all) contract SerializeMetadata { // Serialize each trait as an attribute, building the serialized JSON compatible string let parts: [String] = [] let traitsLength = traits.traits.length - for i, trait in traits.traits { + for trait in traits.traits { let attribute = self.serializeNFTTraitAsAttribute(trait) if attribute == nil { continue