Flow Customizable NFTs

Terminology

SC - smart contract

DB - database

FE - front end

BE - back end

Flow

The overall technical image of the interaction :

Front End <-> Smart Contract <-> Back End

The SC is deployed on chain with the info kept on it:

  • 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

The FE is calling the SC's functions to:

  • 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)

The BE is calling itself every few minutes to:

  • 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

Upgrade & Merge

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.

Technical flow

FE Flow

  • 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

BE Flow

  • 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*

Disassemble

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.

Technical flow

FE Flow

  • 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

BE Flow

  • 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

Assemble

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.

Technical flow

FE Flow

  • 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

BE Flow

  • 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*

Swap

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.

Technical flow

FE Flow

  • 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

BE Flow

  • 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.

Last updated