I'm working with thegraph.com and created a subgraph to index blockchain data from a NFT marketplace smart contract I'm building from scratch, just for my own educational purposes. At the same time I'm using using GraphQL and building queries here for the first time, so I'm not even sure if this is the correct question, but I'll get to the point of what's my ultimate goal with the screenshot below. Here is the subgraph endpoint I'm working with in case someone wants to inspect the schema I have there and play with it: https://api.thegraph.com/subgraphs/name/parenthesislab/cubansea-mumbai-v9/graphql
My desired outcome: Receive this price
value that exists in MarketTokenMinted
type inside the corresponding ERC721tokens
objects i'm getting on this single API response.
My current GraphQL query (produces the response from the screenshot above ^):
query FetchMarketTokens {
account(id: "0xae198b77c760c8d547f796f57c469c0294592ab8") {
id
ERC721tokens(orderBy: identifier, orderDirection: desc, first: 10) {
id
identifier
uri
}
}
marketTokenMinteds(orderBy: tokenId, orderDirection: desc) {
nftContract
price
tokenId
}
}
My current GraphQL schema deployed to this subgraph in The Graph:
# schema.graphql
type MarketTokenMinted @entity {
id: ID!
itemId: BigInt! # uint256
nftContract: Bytes! # address
tokenId: BigInt! # uint256
seller: Bytes! # address
owner: Bytes! # address
price: BigInt! # uint256
sold: Boolean! # bool
}
type MarketTokenSold @entity {
id: ID!
itemId: BigInt! # uint256
nftContract: Bytes! # address
tokenId: BigInt! # uint256
seller: Bytes! # address
owner: Bytes! # address
price: BigInt! # uint256
sold: Boolean! # bool
}
type Account @entity {
id: ID!
asERC721: ERC721Contract
ERC721tokens: [ERC721Token!]! @derivedFrom(field: "owner")
ERC721operatorOwner: [ERC721Operator!]! @derivedFrom(field: "owner")
ERC721operatorOperator: [ERC721Operator!]! @derivedFrom(field: "operator")
ERC721transferFromEvent: [ERC721Transfer!]! @derivedFrom(field: "from")
ERC721transferToEvent: [ERC721Transfer!]! @derivedFrom(field: "to")
events: [Event!]! @derivedFrom(field: "emitter")
}
type ERC721Contract @entity {
id: ID!
asAccount: Account!
supportsMetadata: Boolean
name: String
symbol: String
tokens: [ERC721Token!]! @derivedFrom(field: "contract")
operators: [ERC721Operator!]! @derivedFrom(field: "contract")
transfers: [ERC721Transfer!]! @derivedFrom(field: "contract")
}
type ERC721Token @entity {
id: ID!
contract: ERC721Contract!
identifier: BigInt!
owner: Account!
approval: Account!
uri: String
transfers: [ERC721Transfer!]! @derivedFrom(field: "token")
}
type ERC721Operator @entity {
id: ID!
contract: ERC721Contract!
owner: Account!
operator: Account!
approved: Boolean!
}
type ERC721Transfer implements Event @entity {
id: ID!
emitter: Account!
transaction: Transaction!
timestamp: BigInt!
contract: ERC721Contract!
token: ERC721Token!
from: Account!
to: Account!
}
interface Event {
id: ID!
transaction: Transaction!
emitter: Account!
timestamp: BigInt!
}
type Transaction @entity {
id: ID!
timestamp: BigInt!
blockNumber: BigInt!
events: [Event!]! @derivedFrom(field: "transaction")
}
After countless hours trying to figure this out I'm not sure anymore what I'm missing or how to put this together to receive this price
value along with the rest of the obtained data on each ERC721tokens
objects received. Any help that sets me in the right direction is highly appreciated.
Finally found how, answering my own question here for future reference.
This could be done by adding a price
field into the ERC721Token
entity of my schema. Then I was able to add mapping logic into the event returning price which would load the ERC721Token
entity and save the price information there. This event was MarketTokenMinted
.
The final solution was put together as follows:
The ERC721Token
type with an optional price field added:
type ERC721Token @entity {
id: ID!
contract: ERC721Contract!
identifier: BigInt!
owner: Account!
approval: Account!
uri: String
transfers: [ERC721Transfer!]! @derivedFrom(field: "token")
price: BigInt # uint256
}
The mapping.ts
file with added mapping logic to fetch the token by tokenId
parameter (coming from the MarketTokenMintedEvent
), adds the .price
property and value and save with token.save()
:
import {
MarketTokenMinted as MarketTokenMintedEvent,
MarketTokenSold as MarketTokenSoldEvent,
} from "../generated/CSMarket/CSMarket";
import { MarketTokenMinted, MarketTokenSold } from "../generated/schema";
import { fetchERC721, fetchERC721Token } from "./fetch/erc721";
export function handleMarketTokenMinted(event: MarketTokenMintedEvent): void {
let entity = new MarketTokenMinted(
event.transaction.hash.toHex() + "-" + event.logIndex.toString()
);
entity.itemId = event.params.itemId;
entity.nftContract = event.params.nftContract;
entity.tokenId = event.params.tokenId;
entity.seller = event.params.seller;
entity.owner = event.params.owner;
entity.price = event.params.price;
entity.sold = event.params.sold;
// Add token price value to new .price field in the ERC721Token type.
let contract = fetchERC721(event.params.nftContract);
if (contract != null) {
let token = fetchERC721Token(contract, event.params.tokenId);
token.price = event.params.price;
contract.save();
token.save();
}
entity.save();
}
The FetchMarketTokensByOwner
adding the price field:
query FetchMarketTokensByOwner {
erc721Tokens(
where: {owner: "0xae198b77c760c8d547f796f57c469c0294592ab8"}
orderBy: identifier
orderDirection: desc
first: 10
) {
identifier
uri
owner {
id
}
price
}
}
And the results I'm getting now with the price
value included inside each token object:
{
"data": {
"erc721Tokens": [
{
"identifier": "4",
"uri": "https://ipfs.infura.io/ipfs/QmfZXdugdU6BwtxWDNxpnETviB36qBX9qrLDrxeDSoFept",
"owner": {
"id": "0xae198b77c760c8d547f796f57c469c0294592ab8"
},
"price": "324324520000000"
},
{
"identifier": "3",
"uri": "https://ipfs.infura.io/ipfs/QmW21btPRbB8zgXiLs4oegpGXiLLSX9jnuSip4axwkFdaz",
"owner": {
"id": "0xae198b77c760c8d547f796f57c469c0294592ab8"
},
"price": "343235000000000"
},
{
"identifier": "1",
"uri": "https://ipfs.infura.io/ipfs/QmRKGJMnnLMBeT72bXU6yjG2g2MpHSvrq8pRGbZykmjSgE",
"owner": {
"id": "0xae198b77c760c8d547f796f57c469c0294592ab8"
},
"price": "323424523400000"
}
]
}
}