public-assembly / zora-drops-utils

React hooks and query utils for Zora editions contracts
MIT License
4 stars 2 forks source link

Updated Edition/Drop Querying strategy following Felt Zine meeting #29

Open 0xTranqui opened 1 year ago

0xTranqui commented 1 year ago

@dblodorn @Javier-Szyfer had a great meeting with Felt Zine on friday, but found out that they want to be able to do generative editions (audio metadata same for each token w/ diff cover art - unun style) which uses the dropsMetadataRenderer rather than the editionsMetadataRenderer. Because we'll have to build that strategy out for them, I suggest we also add that flexibility to Neosound as well (this will allow us to curate unun on the platform, which is strongly desired imo since this was one of the key sources of inspiration for the project).

After doing some digging through the drops subgraph, I think I have an idea for a multi part query that will give us flexibility to render either type correctly (this would be run for each contract curated in the curation contract):

  1. Get the renderer address for each contract
**Query:**
query MyQuery {
  erc721Drops(where: {address: "0x532f7DB02D2ebE12f2CDdfAcDa807FD9B2D96F66"}) {
    rendererAddress
  }
}

**Return:
{**
  "data": {
    "erc721Drops": [
      {
        "rendererAddress": "0x5914d9a241008b9f02f22811bf3a77e02b84d226"
      }
    ]
  }
}
  1. Based on the rendererAddress, make the appropriate query depending on if it is an edition or drop:

editionMetadataRenderer = "0xd167b7a408c65306d5a2abead63986540110b28b" dropMetadataRenderer = "0x5914d9a241008b9f02f22811bf3a77e02b84d226"

Edition Metadata Query (this or something like this):

query MyQuery {
  erc721Drops(where: {address: "${editionAddress}"}) {
    name
    editionMetadata {
      contractURI
      description
      animationURI
      imageURI
    }
    owner
    address
    creator
    maxSupply
    totalMinted
    symbol
    salesConfig {
      publicSaleStart
      publicSaleEnd
      publicSalePrice
      maxSalePurchasePerAddress
    }
  }
}

Editition Metadata Return (this or something like this):

{
  "data": {
    "erc721Drops": [
      {
        "name": "☾ ⓵ ☽",
        "editionMetadata": {
          "contractURI": "",
          "description": "The 1st 100 days",
          "animationURI": "",
          "imageURI": "ipfs://bafkreigpdv5kbqm4k7tvpzxaailtpmvsg5kvjftrjuiot5oeqgdzqhqjea"
        },
        "owner": "0x4c53c6d546c9e38db56040ab505460a9187a5281",
        "address": "0x233d15a70bf50b10c5e4ce8f8e3acf2fddb83fe5",
        "creator": "0x4c53c6d546c9e38db56040ab505460a9187a5281",
        "maxSupply": "18446744073709551615",
        "totalMinted": "107",
        "symbol": "100",
        "salesConfig": {
          "publicSaleStart": "1663874216",
          "publicSaleEnd": "1663992000",
          "publicSalePrice": "5000000000000000",
          "maxSalePurchasePerAddress": "4294967295"
        }
      }
    ]
  }
}

Notes on Drops

To get specific metadata for drops style contracts you have to specifiy a token Id. The initial idea is for drops style contracts (which we know before making this second query since we got the metadata renderer address in the first query), we will render metadata for token public-assembly/audio-player-ui#1 of the contract, while still providing the sales config informaiton (mint price, total Minted, max supply, mint start time, etc.) for the contract so it can be minted.

Drops currently act weird in the subgraph, trying to get the drops metadata base info using the query for it returns a null currently. Another thing im thinking is that this could instead be done switching over to the zora indexer to make the follow up query for drops, since the zora api returns parsed metadata files directly

Drops Metadata Query using subgraph (this or something like this):

query MyQuery {
  erc721Drops(where: {address: "${dropAddress}"}) {
    name
    owner
    address
    creator
    maxSupply
    totalMinted
    symbol
    rendererAddress
    salesConfig {
      publicSaleStart
      publicSaleEnd
      publicSalePrice
      maxSalePurchasePerAddress
    }
    dropMetadata {
      base
      contractURI
      extension
    }
  }
}

Drop Metadata Return (this or something like this):

{
  "data": {
    "erc721Drops": [
      {
        "name": "Astrosuka + Sofja - inicio",
        "owner": "0x72338f6dfc380e9488c4853626405419d4660030",
        "address": "0x532f7db02d2ebe12f2cddfacda807fd9b2d96f66",
        "creator": "0x72338f6dfc380e9488c4853626405419d4660030",
        "maxSupply": "404",
        "totalMinted": "117",
        "symbol": "UN000",
        "rendererAddress": "0x5914d9a241008b9f02f22811bf3a77e02b84d226",
        "salesConfig": {
          "publicSaleStart": "0",
          "publicSaleEnd": "50000000000",
          "publicSalePrice": "20000000000000000",
          "maxSalePurchasePerAddress": "404"
        },
        "dropMetadata": null
      }
    ]
  }
}

Drops Metadata Query using Zora Indexer (something like this):

query ListCollections {
  token(
    token: {address: "0x532f7DB02D2ebE12f2CDdfAcDa807FD9B2D96F66", tokenId: "1"}
  ) {
    token {
      collectionAddress
      collectionName
      metadata
    }
  }
}

Drops Metadata Query Return from Zora Indexer (something like this):

{
  "data": {
    "token": {
      "token": {
        "collectionAddress": "0x532f7db02d2ebe12f2cddfacda807fd9b2d96f66",
        "collectionName": "Astrosuka + Sofja - inicio",
        "metadata": {
          "name": "Astrosuka + Sofja - inicio 1",
          "description": "[UN000] music/artwork by astrosuka + sofja | 2022 ✧unun.",
          "animation_url": "ipfs://bafybeidhl3ygczc4b3lfn63mpybkhzpfjdsaz2tafpa35zzvqjfxxwblnq/inicio.mp3",
          "image": "ipfs://bafybeigs4g2j74r44o5lbfegdven7ejoq65mosildkun63r3ct2jjl6emm/0000000.jpg",
          "artist": "Astrosuka + Sofja",
          "title": "inicio",
          "release": "inicio",
          "code": "UN000",
          "trackNumber": "1",
          "attributes": [
            {
              "trait_type": "Artist",
              "value": "Astrosuka + Sofja"
            },
            {
              "trait_type": "mode",
              "value": "light"
            },
            {
              "trait_type": "portal",
              "value": "open"
            },
            {
              "trait_type": "data",
              "value": "consistent"
            },
            {
              "trait_type": "seal",
              "value": "constelacion"
            },
            {
              "trait_type": "watermark",
              "value": "none"
            }
          ]
        }
      }
    }
  }
}
0xTranqui commented 1 year ago

more thoughts:

I would imagine we would want to normalize all of the data, so that the final cleaned info for both drops/editions can be passed into an NFTCard style component in the same way. So pretty much we would be fetching + normalizing the collection wide metadata for edition style contracts, and fetching + normalizing the metadata for token Id public-assembly/audio-player-ui#1 for drops style contracts. imagine that being something like:

-creator -owner -address -name/title -description -imageURI -animationURI -contract wide salesConfig stuff (to facilitate minting)

This also will make it easy for ppl to swap in and out metadata fetching strategies (ex: for ppl who want to curate things other than zora style nft contracts), as there will be a standardized prop list required to pass into the NFTCard component

dblodorn commented 1 year ago

Yeah this is rad. Good serendipity around the request to do a drop.

Should be pretty easy to configure and expose as a flexible hook.

dblodorn commented 1 year ago

@0xTranqui cool to move this issue to: https://github.com/public-assembly/zora-drops-utils ...this logic should be in that package.