Flow Customizable NFTs
Last updated
Last updated
SC - smart contract
DB - database
FE - front end
BE - back end
the component smart contracts have maps pointing from component-name to component-uri
the upgrade smart contract has queues for every type of operation (merge/assemble/disable/swap) and holds key information in order for the backend to know what happened and use its functions afterwards
move an NFT from an old collection (Miami / NYC) to the new StacksDegens collection <-> the merge function (the call burns the old NFT and add its ID and type to a merge-queue)
disassemble an existing Degen (the call burns that specific StacksDegen and adds its ID and OWNER to a disassemble-queue)
assemble a Degen from existing components (background, car, head, rim) (the call burns those specific components and adds those IDs and OWNER to an assemble-queue)
swap Degen with component (the call burns the StacksDegen and the component and adds ID Degen, ID component, type component and OWNER to a swap-queue)
check what got disassembled and proceeds with calling the appropriate functions for that
check what got assembled and proceeds with calling the appropriate functions for that
check what got merged and proceeds with calling the appropriate functions for that
check what got swapped and proceeds with calling the appropriate functions for that
Explained with Stacks Degens.
There are 2 OG Collections: NYC Degens and Miami Degens.
The first operation is upgrade
(also known as merge in this case). It creates a new collection in which the equivalent StacksDegens are minted after the ones from the old collections are burnt.
This is done by keeping a queue with the burnt NFTs in the smart contract and letting the admin take the values from there, fetch the off-chain data (most of it from Pinata), do the operations to create the new StacksDegens(JSON and image ) and upload it. Then, the admin calls the mint for that user and gives him the upgraded version for what he previously owned.
FE user burns his Degen NFT and the wanted component and calls (define-public (prepare-upgrade (degen-id uint) (degen-type (string-ascii 30)))
Degen Id, Degen Type are stored on the SC for BE operations
SC upgrade-contract: get value from queue (define-read-only (get-merge-work-queue)
=> (degen-id, degen-type, address)
SC component: call read only get-token-uri
for degen type SC with given ID
fetch JSON
Convert old values to new ones - map from JSON to new values ( it is a map that for an old attribute has a new corresponding one)
For each component converted
call car/background/head/rims get-name-url
fetch JSON component
get image attribute
save the 2 images locally to ('generated-degens')
add them in json as image attribute and properties.image_game attribute
DB Get Id*
Create json (name#id, img hash, attributes, collection("DegenNFT"))
Pinata upload json and get hash ("ipfs://" + hash)
SC upgrade-contract: call merge_finalize(member as address, json_hash as Degen uri)
DB increment id*
This gives the ability to separate the Stacks Degen into components, each from its collection. Burn a Stacks Degens NFT and mint the components included in its metadata URI.
FE user burns his Degen NFT from selecting it calling (define-public (prepare-disassemble (token-id uint))
Degen Id is stored on the SC for BE operations
SC upgrade-contract: get value from disassemble queue (define-read-only (get-disassemble-work-queue)
=> (degen-id, address)
(define-read-only (get-token-uri (token-id uint))
fetch JSON
SC degens: take json of selected Degen NFT
Get components from JSON:
name:
background: attributes-background → value ( same for car, head and rims )
SC upgrade-contract: call disassemble_finalize (addressToGetComponents, background_name, car_name, rims_name, head_name)
mint to the address the components with the names fetched in the prior step
This gives the ability to assemble different components, creating a StacksDegens NFT. Burns the different components, one from each collection, and mint the Stacks Degens NFT.
FE user burns his Degen NFT and the wanted component and calls (define-public (prepare-upgrade (degen-id uint) (degen-type (string-ascii 30)))
Component Ids are stored on the SC for BE operations
SC upgrade-contract: get value from queue (define-read-only (get-assemble-work-queue)
=> (background_id, car_id, rims_id, head_id, member as owner)
call read-only get-token-uri for each of these 4 IDs ( gets a json )
fetch jsJSONon
SC every component: get the attribute's values & image (url) from json
background, rims, car, head direct the value
create images for Degen by combining all images: background_url, rims_url, car_url, head_url
save the 2 images locally to ('generated-degens')
add them in json as image attribute and properties.image_game attribute
DB Get Id*
Create json (name#id, img hash, attributes, collection("DegenNFT"))
Upload the image on Pinata and get the hash ("ipfs://" + hash)
SC upgrade-contract: call assemble_finalize with (member as address, json_hash as uri)
DB increment Id*
This gives the ability to swap different components, creating a new StacksDegens NFT. Burns the component which is added to the new NFT and mints the old component swapped from the old StacksDegens NFT, alongside the new StacksDegens NFT.
User selects one component from every collection. Calls (define-public (prepare-swap (degen-id uint) (component-id uint) (component-type (string-ascii 30)))
for the selected ids and burns the components.
Degen Id is stored on the SC for BE operations
SC upgrade-contract: get value from queue (define-read-only (get-swap-work-queue)
=> ( degen id, component id, component type, member as owner )
call read-only get-token-uri Degen ID
call read-only get-token-uri component ID from the specific type SC
keep aux value (component-name, component-type) from Degen that is replaced
take all attributes from Degen json ( old + the new overwritten component)
for each attribute
get name-url
fetch json
get image(url)
save the 2 images locally to ('generated-degens')
add them in json as image attribute and properties.image_game attribute
DB Get Id *
create json (name#id, img hash, attributes, collection("DegenNFT"))
Upload the image on Pinata and get the hash ("ipfs://" + hash)
SC upgrade-contract: call swap_finalize with (member, json_hash as Dege uri, component-name, component-type)
DB increment id*
*A simple db is required to keep the ID of the current Degen that will be minted so it is also added into the json file. When an operation is performed it gets incremented.