Skip to content

Commit

Permalink
Merge pull request #441 from ourzora/add-metadata-update-to-subgraph
Browse files Browse the repository at this point in the history
Add custom metadata support to subgraph
  • Loading branch information
neokry authored Feb 28, 2024
2 parents e230be8 + 04f1ccf commit 928a1b4
Show file tree
Hide file tree
Showing 21 changed files with 1,166 additions and 872 deletions.
715 changes: 352 additions & 363 deletions apps/subgraph/abis/Manager.json

Large diffs are not rendered by default.

251 changes: 251 additions & 0 deletions apps/subgraph/abis/MetadataRendererBase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
[
{
"type": "function",
"name": "contractImage",
"inputs": [],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "contractURI",
"inputs": [],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "contractVersion",
"inputs": [],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "pure"
},
{
"type": "function",
"name": "description",
"inputs": [],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "getAdditionalTokenProperties",
"inputs": [],
"outputs": [
{
"name": "_additionalTokenProperties",
"type": "tuple[]",
"internalType": "struct IBaseMetadata.AdditionalTokenProperty[]",
"components": [
{ "name": "key", "type": "string", "internalType": "string" },
{ "name": "value", "type": "string", "internalType": "string" },
{ "name": "quote", "type": "bool", "internalType": "bool" }
]
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "initialize",
"inputs": [
{ "name": "initStrings", "type": "bytes", "internalType": "bytes" },
{ "name": "token", "type": "address", "internalType": "address" }
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "onMinted",
"inputs": [{ "name": "tokenId", "type": "uint256", "internalType": "uint256" }],
"outputs": [{ "name": "", "type": "bool", "internalType": "bool" }],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "owner",
"inputs": [],
"outputs": [{ "name": "", "type": "address", "internalType": "address" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "projectURI",
"inputs": [],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "setAdditionalTokenProperties",
"inputs": [
{
"name": "_additionalTokenProperties",
"type": "tuple[]",
"internalType": "struct IBaseMetadata.AdditionalTokenProperty[]",
"components": [
{ "name": "key", "type": "string", "internalType": "string" },
{ "name": "value", "type": "string", "internalType": "string" },
{ "name": "quote", "type": "bool", "internalType": "bool" }
]
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "supportsInterface",
"inputs": [{ "name": "_interfaceId", "type": "bytes4", "internalType": "bytes4" }],
"outputs": [{ "name": "", "type": "bool", "internalType": "bool" }],
"stateMutability": "pure"
},
{
"type": "function",
"name": "token",
"inputs": [],
"outputs": [{ "name": "", "type": "address", "internalType": "address" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "tokenURI",
"inputs": [{ "name": "tokenId", "type": "uint256", "internalType": "uint256" }],
"outputs": [{ "name": "", "type": "string", "internalType": "string" }],
"stateMutability": "view"
},
{
"type": "function",
"name": "updateContractImage",
"inputs": [
{ "name": "_newContractImage", "type": "string", "internalType": "string" }
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "updateDescription",
"inputs": [{ "name": "_newDescription", "type": "string", "internalType": "string" }],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "updateProjectURI",
"inputs": [{ "name": "_newProjectURI", "type": "string", "internalType": "string" }],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "AdditionalTokenPropertiesSet",
"inputs": [
{
"name": "_additionalJsonProperties",
"type": "tuple[]",
"indexed": false,
"internalType": "struct IBaseMetadata.AdditionalTokenProperty[]",
"components": [
{ "name": "key", "type": "string", "internalType": "string" },
{ "name": "value", "type": "string", "internalType": "string" },
{ "name": "quote", "type": "bool", "internalType": "bool" }
]
}
],
"anonymous": false
},
{
"type": "event",
"name": "BatchMetadataUpdate",
"inputs": [
{
"name": "_fromTokenId",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "_toTokenId",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "ContractImageUpdated",
"inputs": [
{
"name": "prevImage",
"type": "string",
"indexed": false,
"internalType": "string"
},
{ "name": "newImage", "type": "string", "indexed": false, "internalType": "string" }
],
"anonymous": false
},
{
"type": "event",
"name": "DescriptionUpdated",
"inputs": [
{
"name": "prevDescription",
"type": "string",
"indexed": false,
"internalType": "string"
},
{
"name": "newDescription",
"type": "string",
"indexed": false,
"internalType": "string"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Initialized",
"inputs": [
{ "name": "version", "type": "uint64", "indexed": false, "internalType": "uint64" }
],
"anonymous": false
},
{
"type": "event",
"name": "MetadataUpdate",
"inputs": [
{
"name": "_tokenId",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "WebsiteURIUpdated",
"inputs": [
{ "name": "lastURI", "type": "string", "indexed": false, "internalType": "string" },
{ "name": "newURI", "type": "string", "indexed": false, "internalType": "string" }
],
"anonymous": false
},
{ "type": "error", "name": "InvalidInitialization", "inputs": [] },
{ "type": "error", "name": "NotInitializing", "inputs": [] },
{ "type": "error", "name": "ONLY_MANAGER", "inputs": [] },
{ "type": "error", "name": "ONLY_OWNER", "inputs": [] },
{ "type": "error", "name": "ONLY_TOKEN", "inputs": [] },
{
"type": "error",
"name": "TOKEN_NOT_MINTED",
"inputs": [{ "name": "tokenId", "type": "uint256", "internalType": "uint256" }]
}
]
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/subgraph/config/sepolia.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"address": "0x0ca90a96ac58f19b1f69f67103245c9263bc4bfc",
"startBlock": 5074430
},
"callHandlers": true
"callHandlers": false
}
19 changes: 10 additions & 9 deletions apps/subgraph/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@
"prepare:optimism-sepolia": "mustache config/optimism-sepolia.json subgraph.yaml.mustache > subgraph.yaml",
"prepare:zora": "mustache config/zora.json subgraph.yaml.mustache > subgraph.yaml",
"prepare:zora-sepolia": "mustache config/zora-sepolia.json subgraph.yaml.mustache > subgraph.yaml",
"deploy:sepolia": "pnpm clean && pnpm prepare:sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-sepolia-testnet/1.1.0",
"deploy:mainnet": "pnpm clean && pnpm prepare:mainnet && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-ethereum-mainnet/1.1.0",
"deploy:base": "pnpm clean && pnpm prepare:base && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-mainnet/1.1.0",
"deploy:base-sepolia": "pnpm clean && pnpm prepare:base-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-sepolia/1.1.0",
"deploy:optimism": "pnpm clean && pnpm prepare:optimism && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-mainnet/1.1.0",
"deploy:optimism-sepolia": "pnpm clean && pnpm prepare:optimism-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-sepolia/1.1.0",
"deploy:zora": "pnpm clean && pnpm prepare:zora && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-mainnet/1.1.0",
"deploy:zora-sepolia": "pnpm clean && pnpm prepare:zora-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-sepolia/1.1.0",
"deploy:sepolia": "pnpm clean && pnpm prepare:sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-sepolia-testnet/1.2.0",
"deploy:mainnet": "pnpm clean && pnpm prepare:mainnet && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-ethereum-mainnet/1.2.0",
"deploy:base": "pnpm clean && pnpm prepare:base && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-mainnet/1.2.0",
"deploy:base-sepolia": "pnpm clean && pnpm prepare:base-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-base-sepolia/1.2.0",
"deploy:optimism": "pnpm clean && pnpm prepare:optimism && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-mainnet/1.2.0",
"deploy:optimism-sepolia": "pnpm clean && pnpm prepare:optimism-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-optimism-sepolia/1.2.0",
"deploy:zora": "pnpm clean && pnpm prepare:zora && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-mainnet/1.2.0",
"deploy:zora-sepolia": "pnpm clean && pnpm prepare:zora-sepolia && pnpm codegen && graph build && goldsky subgraph deploy nouns-builder-zora-sepolia/1.2.0",
"create:local": "graph create --node http://localhost:8020/ nouns-builder",
"remove:local": "graph remove --node http://localhost:8020/ nouns-builder",
"deploy:local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 --network sepolia nouns-builder"
},
"dependencies": {
"@graphprotocol/graph-cli": "0.50.1",
"@graphprotocol/graph-ts": "0.30.0"
"@graphprotocol/graph-ts": "0.30.0",
"as-base64": "^0.2.0"
},
"devDependencies": {
"matchstick-as": "0.5.0",
Expand Down
1 change: 1 addition & 0 deletions apps/subgraph/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Token @entity {
id: ID!
name: String!
image: String
content: String
tokenContract: Bytes!
tokenId: BigInt!
owner: Bytes!
Expand Down
60 changes: 54 additions & 6 deletions apps/subgraph/src/manager.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { DAODeployed as DAODeployedEvent } from '../generated/Manager/Manager'
import { AuctionConfig, DAO } from '../generated/schema'
import {
DAODeployed as DAODeployedEvent,
MetadataRendererUpdated as MetadataRendererUpdatedEvent,
} from '../generated/Manager/Manager'
import { AuctionConfig, DAO, Token } from '../generated/schema'
import {
Auction as AuctionTemplate,
Governor as GovernorTemplate,
MetadataRenderer as MetadataRendererTemplate,
Token as TokenTemplate,
} from '../generated/templates'
import { Auction as AuctionContract } from '../generated/templates/Auction/Auction'
import { MetadataRenderer as MetadataContract } from '../generated/templates/MetadataRenderer/MetadataRenderer'
import { MetadataRendererBase as MetadataRendererBaseContract } from '../generated/templates/MetadataRendererBase/MetadataRendererBase'
import { Token as TokenContract } from '../generated/templates/Token/Token'
import { createMetadataRendererTemplate } from './utils/createMetadataRendererTemplate'
import { setTokenMetadata } from './utils/setTokenMetadata'
import { BigInt, DataSourceContext } from '@graphprotocol/graph-ts'

export function handleDAODeployed(event: DAODeployedEvent): void {
let tokenContract = TokenContract.bind(event.params.token)
let metadataContract = MetadataContract.bind(event.params.metadata)
let metadataContract = MetadataRendererBaseContract.bind(event.params.metadata)
let auctionContract = AuctionContract.bind(event.params.auction)

let auctionConfig = new AuctionConfig(event.params.token.toHexString())
Expand Down Expand Up @@ -57,6 +61,50 @@ export function handleDAODeployed(event: DAODeployedEvent): void {
let ctx = new DataSourceContext()
ctx.setString('tokenAddress', event.params.token.toHexString())

MetadataRendererTemplate.createWithContext(event.params.metadata, ctx)
createMetadataRendererTemplate(metadataContract, event.params.metadata, ctx)
AuctionTemplate.createWithContext(event.params.auction, ctx)
}

export function handleMetadataRendererUpdated(event: MetadataRendererUpdatedEvent): void {
let metadataContract = MetadataRendererBaseContract.bind(event.params.renderer)

// If token function reverts this contract does not implement the BaseMetadata interface and cannot be indexed
let tokenAddress = metadataContract.try_token()
if (tokenAddress.reverted) return

let dao = DAO.load(tokenAddress.value.toHexString())

if (!dao) return

let tokenContract = TokenContract.bind(tokenAddress.value)

// Update DAO metadata
dao.description = metadataContract.description()
dao.contractImage = metadataContract.contractImage()
dao.projectURI = metadataContract.projectURI()

dao.save()

// Update token metadata
let totalSupply = tokenContract.totalSupply()
for (let i = BigInt.fromI32(0); i < totalSupply; i.plus(BigInt.fromI32(1))) {
let tokenId = `${event.address.toHexString()}:${i.toString()}`
let token = Token.load(tokenId)
if (!token) continue

let tokenURI = tokenContract.try_tokenURI(i)
if (!tokenURI.reverted) {
setTokenMetadata(token, tokenURI.value)
} else {
token.name = `${tokenContract.name()} #${i.toString()}`
token.image = null
token.content = null
}
token.save()
}

// Create new metadata renderer template
let ctx = new DataSourceContext()
ctx.setString('tokenAddress', tokenAddress.value.toHexString())
createMetadataRendererTemplate(metadataContract, event.params.renderer, ctx)
}
Loading

0 comments on commit 928a1b4

Please sign in to comment.