Liveminting NFTs with the Wolfram Language on the Cardano Blockchain
When I am at blockchain conferences, holding sales calls, at the grocery store, on an elevator or pretty much anywhere, I find myself explaining why I believe that non-fungible tokens (NFTs) are one of the most exciting new areas of technology.
During my time as CEO of Wolfram Blockchain Labs (WBL), I’ve worked with our team on innovative areas in smart contracts, computational contracts and computational facts. Our current view of smart contracts is much different from four or five years ago, when we first plunged into decentralized technologies.
Originally, we thought computational contracts and smart contracts would have broad applications and that both companies and consumers would deploy them via a wide array of uses right away. The expansion of smart and computational contracts, however, has only occurred in discrete areas with strong consumer interest—such as smart contract–defined utility tokens and NFTs.
So it is exciting to announce the Wolfram Language–Cardano blockchain integration will be used to create our first public set of NFTs using Wolfram Language tools at our inaugural liveminting event.
NFTs Are More Than Speculation; They Showcase Our Digital Lives
NFTs have grabbed the digital spotlight in recent months, making an enormous cultural impact and capturing the zeitgeist of digital assets, perhaps best highlighted by this March 2021 skit on Saturday Night Live:
what the hell’s an NFT pic.twitter.com/BcFylopM63
— Saturday Night Live – SNL (@nbcsnl) March 28, 2021
Unfortunately, much of the general discussion on NFTs has focused on speculation in digital art. At WBL, we think there is so much more to NFTs than speculation and believe they will become a large part of our general digital footprint.
Our digital lives have become both a reflection of our physical lives and a way to show our affiliations, collections and perhaps even credentials. At WBL, we’ve been fascinated with exploring various types of “experiential” NFTs that highlight these physical experiences and affiliations:
- Collectible NFTs: Collecting items is a critical part of our lives, and collectible NFTs are digital-scarce items that can be collected, traded, traced and shown to others.
- Credential NFTs: Perhaps better defined as non-fungible records, these NFTs allow us to limit the sharing of our achievements, and if shared, trace this across an ecosystem in verifiable ways.
- Programmatic NFTs: These NFTs make use of the programmable features of the underlying smart contracts to react to the owners and the environment—through computational facts, of course!
Liveminting: A New Kind of Digital Event
We are pleased to use some of our own Wolfram Language tools to livemint NFTs during a panel led by Wolfram founder and CEO Stephen Wolfram.
Liveminting, which creates NFTs in real time, allows you to include your audience in the unique experience of adding NFTs to the blockchain. NFTs don’t just prove ownership of an asset: they are computable artifacts that can create innovative economic and business models as well as novel ways of expanding audiences and connecting communities. Experiential NFTs can digitally capture and document important life events, but the truly unique aspect of experiential NFTs is the minting process—and through liveminting, the minting process is transformed from a technical process into a communal event.
In the past, the experience of creating an item to represent a memorable occasion was a special event in and of itself. Posing for a daguerreotype in the mid-1800s involved staying in the same position for up to 12 minutes! Because taking pictures using early photo technology was an expensive and tedious process, photography was reserved for the most significant life events such as weddings or births, but having a physical representation of those cherished moments for posterity was well worth the effort.
While advanced photo technology provides us with the luxury of taking, saving and sharing pictures quickly and easily—from posting your dinner to social media to sending pictures of your newborn baby to your parents. The moments we document through photography are still crucial, but the process of taking the picture is no longer a special event in and of itself—and that’s where experiential NFTs come in.
During our inaugural liveminting event, “Stephen Wolfram’s Picks of Cellular Automata from the Computational Universe” at 1pm CDT on July 27, 2021, Stephen Wolfram and a panel of Wolfram experts will programmatically select and generate cellular automata images and livemint NFTs for each image. Join us on Twitch or YouTube, and be sure to sign up for your chance to win an NFT from the event.
NFT Minting Tools Powered by the Wolfram Language
NFT minting combines creative artwork, programs or some other concept with a specific transaction structure for a blockchain. Our example here focuses on artwork generated by code.
We begin generating a piece of artwork by outlining the general structure of a cellular automaton and color themes, but leave some decisions to the computer:
$colors = {"Rainbow", "LakeColors", "NeonColors", "SolarColors", "GreenPinkTones", "FruitPunchColors", "RustTones", "ValentineTones", "DarkRainbow", "CherryTones"};
ca4 = ArrayPlot[ CellularAutomaton[<|"Dimension" -> 2, "OuterTotalisticCode" -> RandomInteger[{574, 777}]|>, {{Table[1, 7]}, 0}, {{{150}}}], ColorFunction -> RandomChoice[$colors]]
word = RandomWord[]; caProduced = ImageCompose[ca4, Rasterize[ Text[Style[word, Pink, 24, Background -> None], Background -> None], Background -> Black]]
This is the image we created as a human-computer team! The computer chose the cellular automaton rule, colors and a random word to be used as the NFT name.
Now we just need to provide the basic NFT details, including the name generated by the computer and the manually written description. We also provided our private key, which allows the MintNFT function to take care of the remaining minting process:
ourNFT = ResourceFunction[ ResourceObject[ Association[ "Name" -> "MintNFT", "UUID" -> "03503355-73e0-45de-8ed1-565928256b64", "ResourceType" -> "Function", "Description" -> "Function to mint NFTs", "ResourceLocations" -> { CloudObject[ "https://www.wolframcloud.com/obj/christianp/Resources/035/\ 03503355-73e0-45de-8ed1-565928256b64"]}, "Version" -> None, "ContributorInformation" -> Association[ "ContributedBy" -> "Piero Snchez, Christian Pasquel"], "Documentation" -> Association["Usage" -> { Association["Usage" -> BoxData[ RowBox[{ StyleBox[ RowBox[{ StyleBox["ResourceFunction", "ResourceFunctionSymbol"], "[", StyleBox["\"MintNFT\"", "ResourceFunctionName"], "]"}], "ResourceFunctionHandle"], "[", RowBox[{"nftSpec", ",", " ", "cryptoSpec"}], "]"}]], "Description" -> TextData[{"explanation of what use of the argument ", StyleBox["arg", "TI"], " does."}]]}, "Notes" -> { Cell[ TextData[{ Cell[ BoxData[ StyleBox["nftSpec", "TI"]], "InlineFormula", FontFamily -> "Source Sans Pro"], " is an association with the following keys:"}], "Notes", TaggingRules -> {}, CellEventActions -> { Inherited, {"KeyDown", "\t"} :> Replace[SelectionMove[ SelectedNotebook[], After, Cell]; NotebookFind[ SelectedNotebook[], "TabNext", Next, CellTags, AutoScroll -> True, WrapAround -> True], Blank[NotebookSelection] :> SelectionMove[ SelectedNotebook[], All, CellContents, AutoScroll -> True]], PassEventsDown -> False, PassEventsUp -> False}, CellChangeTimes -> {{3.834596709859942*^9, 3.834596728253275*^9}}, CellTags -> "TabNext", CellID -> 521904482], Cell[ BoxData[ GridBox[{{ Cell["\"Name\"", "TableText"], Cell["name of the NFT", "TableText"]}, { Cell["\"Thumbnail\"", "TableText"], Cell["thumbnail image of the NFT", "TableText"]}, { Cell["\"Source\"", "TableText"], Cell["source data of the NFT", "TableText"]}, { Cell["\"Description\"", "TableText"], Cell["description of the NFT", "TableText"]}, { Cell["\"Expression\"", "TableText"], Cell["Wolfram Language expression associated to the NFT", "TableText"]}, { Cell["\"Notebook\"", "TableText"], Cell["Wolfram notebook associated to the NFT", "TableText"]}, { Cell["\"NFTID\"", "TableText"], Cell[ TextData[{ Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "True", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/True", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " to create an autogenerated ID for the NFT"}], "TableText"]}}]], "TableNotes", TaggingRules -> {}, CellChangeTimes -> {{3.834509197802949*^9, 3.834509232395335*^9}, {3.834509397148093*^9, 3.834509425244145*^9}, {3.834509513670753*^9, 3.8345095238353767`*^9}, {3.83450958164635*^9, 3.83450958556153*^9}, {3.834509842811468*^9, 3.834509847046021*^9}, {3.834510044430475*^9, 3.8345100484105797`*^9}, {3.834510414843872*^9, 3.834510451946617*^9}, {3.834510516956297*^9, 3.834510545563621*^9}, {3.834510811563737*^9, 3.834510841394864*^9}, {3.8345110556001663`*^9, 3.834511078382011*^9}, {3.834596033194076*^9, 3.834596033863763*^9}}, CellID -> 1668927828], Cell[ TextData[{ Cell[ BoxData["\"Thumbnail\""], "InlineFormula", FontFamily -> "Source Sans Pro"], " can be a ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "File", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/File", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " containing the path to an image file, or an expression \ such as ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Image", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Image", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], ", ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Graphics", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Graphics", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " or ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Graphics3D", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Graphics3D", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], ". Ideally, the image size should be less than 1MB."}], "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.834595513924712*^9, 3.834595525089054*^9}, {3.834595637071911*^9, 3.834595751276716*^9}, {3.8345958723950777`*^9, 3.8345958915183153`*^9}}, CellID -> 1862320219], Cell[ TextData[{"\"Source\" can be a ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "File", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/File", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " containing the path to the source file associated to \ the NFT, or an expression such as ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Image", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Image", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], ", ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Graphics", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Graphics", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " or ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "Graphics3D", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/Graphics3D", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], "."}], "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.834595867035265*^9, 3.834596001722476*^9}}, CellID -> 1823174241], Cell[ TextData[{"\"Notebook\" is a ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "File", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/File", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " containing the path to a notebook associated to the \ NFT."}], "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.834596041533476*^9, 3.8345960684273853`*^9}}, CellID -> 2066750818], Cell["The maximum string length of \"Expression\" is 64 characters.", "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.8345961200263233`*^9, 3.834596151260285*^9}}, CellID -> 1952945609], Cell[ TextData[{"When \"NFTID\" is ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "True", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/True", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], ", an ID will be autogenerated using the current ", Cell[ BoxData[ TagBox[ ButtonBox[ StyleBox[ "UnixTime", "SymbolsRefLink", ShowStringCharacters -> True, FontFamily -> "Source Sans Pro"], BaseStyle -> Dynamic[ FEPrivate`If[ CurrentValue["MouseOver"], { "Link", FontColor -> RGBColor[0.854902, 0.396078, 0.145098]}, { "Link"}]], ButtonData -> "paclet:ref/UnixTime", ContentPadding -> False], MouseAppearanceTag["LinkHand"]]], "InlineFormula", FontFamily -> "Source Sans Pro"], " and a random integer. Note this is an accessory \ metadata ID used for readability when sharing the NFT details. This \ ID does not identify the NFT on the blockchain."}], "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.834596112167201*^9, 3.834596113678781*^9}, {3.8345961581086817`*^9, 3.8345962032025537`*^9}, {3.834596298351859*^9, 3.834596369033736*^9}, {3.834596793295849*^9, 3.834596794061366*^9}}, CellID -> 724728888], Cell["Files associated to the NFT such as the ones specified by \ \"Thumbnail\", \"Source\" and \"Notebook\" will be automatically \ uploaded to IPFS and their Content Identifiers (CIDs) will be added \ to the NFT's on-chain metadata", "Notes", TaggingRules -> {}, CellChangeTimes -> {{3.834596390524067*^9, 3.834596510042543*^9}}, CellID -> 1694615180]}], "DocumentationLink" -> URL[ "https://www.wolframcloud.com/obj/christianp/DeployedResources/\ Function/MintNFT"], "ExampleNotebookData" -> Automatic, "FunctionLocation" -> CloudObject[ "https://www.wolframcloud.com/obj/christianp/Resources/035/\ 03503355-73e0-45de-8ed1-565928256b64/download/DefinitionData"], "ShortName" -> "MintNFT", "SymbolName" -> "FunctionRepository`$0350335573e045de8ed1565928256b64`MintNFT"]]]\ [<| "Name" -> "Credulously", "Thumbnail" -> ImageResize[caProduced, 200], "Source" -> caProduced, "Description" -> "Word on a rug by Chapin & XTIAN. @chapinshadow @geekykidstuff." |>, <|"OwnerAddress" -> "addr_test1vzhrm3n23affgq8puv98uvgl66ltq229kjdwywydpncth6s6qcay0" , "PrivateKey" -> PrivateKey[ Association[ "Type" -> "EdwardsCurve", "CurveName" -> "ed25519", "PrivateByteArray" -> ByteArray[{237, 8, 131, 222, 32, 39, 248, 112, 214, 141, 22, 16, 102, 227, 125, 86, 82, 0, 56, 149, 201, 24, 204, 61, 139, 176, 12, 221, 108, 105, 229, 212}], "PublicByteArray" -> ByteArray[{29, 155, 185, 55, 238, 186, 94, 38, 87, 76, 116, 115, 73, 54, 35, 205, 224, 27, 202, 164, 198, 220, 185, 27, 172, 210, 133, 159, 208, 71, 61, 6}], "PublicCurvePoint" -> { 496099310087615807537736611896153409352158423583257123153152659\ 92683363825546, 28221504109103146108686670828650211176651621327844746979676808\ 81260752378653}]] |>, "Preview" -> False]
Our NFT was successfully submitted to the Cardano testnet blockchain. The details are expanded here as a Dataset:
Dataset[ourNFT]
We now have the transaction ID (txid) that contains the NFT we just minted:
txid = ourNFT["TransactionID"]
Using the transaction ID, we can see the transaction data using BlockchainTransactionData:
BlockchainTransactionData[txid, BlockchainBase -> {"Cardano", "Testnet"}] // Dataset
The information is also available on the Cardano testnet explorer:
CloudGet["https://wolfr.am/X7ugIld7"]
Extract the metadata from the transaction to retrieve the image we generated and linked to the NFT:
nftMetadata = Values[ Values[ BlockchainTransactionData[txid, "Metadata", BlockchainBase -> {"Cardano", "Testnet"}]][[1]]]; nftMetadata // Dataset
The image is stored on IPFS. To get the image itself, use the IPFS content identifier (CID) linking to the artwork:
nftCID = StringDrop[Values[nftMetadata[[1]]][[1]]["src"], 7]
Then download the image from IPFS:
nftFile = ExternalStorageDownload[nftCID]
Import[nftFile]
Now we can use it locally, such as with this phone background:
CloudGet["https://wolfr.am/X7uhcxVd"]
More to Come on Cardano
We’ve had the opportunity to work closely with IOHK, Coti and other teams supporting the Cardano blockchain. More great things are coming to the Cardano blockchain and community:
- Blockchain integration: Integrating the Cardano blockchain into the Wolfram Language and technologies makes NFT minting tools possible.
- Computational facts and Oracle: WBL and IOHK are bringing computational facts from Wolfram|Alpha to the Cardano blockchain.
- Cardano’s Project Catalyst: WBL is working on guidelines for participation with innovative, community-driven projects.
Liveminting is the latest development from Wolfram, designed for both retail users and developers, and created using Wolfram technologies. We look forward to creating more services for end users to employ blockchain technologies.
Connect with Wolfram Blockchain Labs to find out about integrating your blockchain into the Wolfram Language or a liveminting project on Cardano. Connect with Wolfram Technical Consulting to start a blockchain project. |
Comments