Pre-requisites:
Here we are implementing the outline for NFT entities to be indexed and for instances to be added to the database.
After running yarn codegen
it will generate the schema for this entity.
type NFT @entity {
id: ID!
owner: String!
uri: String!
}
In order to populate the database these NFT
entities, we must have a way of constructing them from incoming on-chain data.
/* In this first section, you can see that we are passing a CosmosEvent into the function,
which we are then dissecting to get a reference to the related NFT Mint message */
export async function handleNFTMint(event: CosmosEvent): Promise<void> {
logger.info(`[NFT Mint Handled]`);
const event_msg = event.msg?.msg?.decodedMsg;
const mint_msg = event_msg?.msg?.mint;
// Here we are deconstructing the mint message into its components
const id = mint_msg.token_id;
const owner = mint_msg.owner;
const uri = mint_msg.token_uri;
// Next, we take these component values and plug them into our new NFT, and save it
const nftEntity = NFT.create({
id,
owner,
uri
});
await nftEntity.save();
}
N.B: Don't forget to import the NFT type from schema.graphql:
import {NFT} from "../types";
Now that we have an NFT
schema, and a handler to construct one, we need to be able to recognise when an NFT Mint event occurs and to pass our handler the correct on-chain data.
Which in this case, is an Event.
handlers:
- handler: handleNFTMint # Here we reference our handler function
kind: cosmos/EventHandler # We are looking for Cosmos events
filter:
type: "execute" # Filtering for 'execute' events or contract executions
messageFilter: # Looking at the related message to the event
type: "/cosmwasm.wasm.v1.MsgExecuteContract"
contractCall: "mint" # We are looking for contract executions that call 'mint'
In project.yaml
, we can also configure which network we would like to index:
# Local Node
endpoint: http://fetch-node:26657
chainId: fetchchain
startBlock: 1
Other network info can be found here, such as Mainnet and Dorado testnet.
In order to reflect our changes, a number of commands have to be run. Which, in this example, have been compiled into a yarn script, yarn dev
.
yarn dev
is comprised of several commands:
docker compose down -v
- make sure any previous docker containers are not runningsudo rm -rf .data/
- wipe the locally stored databasesubql codegen
- generate entity types from the schemasubql build
- compile the@subql
environmentdocker compose pull
- pull the latest docker imagesdocker compose up -d --remove-orphans
- spin up all containers
yarn log
should then be called to output the logs of our indexer.
A great way to deploy and manage contracts is to use the Fetch.ai tool, Jenesis. In this example, we'll use this tool to deploy and execute an NFT contract to test out our new indexer coverage.
The configuration for Jenesis has already been completed within this example repo - however, if you would like to learn how this was constructed, all information should be in the link above.
All of this config can be viewed or edited within the jenesis.toml
file.
In order to deploy anything to our local network, we need to have some currency on a test account.
In the docker-compose.yml
file, there is a fetch network node configured with a validator account. However, we need access to that account to use it - so we recover the account to our local testing keyring in order to leverage it.
fetchd config keyring-backend test
fetchd keys add validator --recover
After running the recovery command, we input the validator's mnemonic:
nut grocery slice visit barrel peanut tumble patch slim logic install evidence fiction shield rich brown around arrest fresh position animal butter forget cost
This can also be found in the docker-compose.yml
.
N.B Ensure the keyring-backend variable value is the same as that set in the jenesis.toml
, in this case the value is test
.
Now that we have an account with coins on our network, we need to compile our contract.
jenesis compile
After this we need to store the contract on-chain, in order to be able to call execution messages on it later.
jenesis deploy validator
This command should come back with a green tick to say that our contract has been deployed successfully.
Minting the NFT requires us to construct a contract execution message in the custom Jenesis shell:
jenesis shell
Here we put together the pieces of our mint message, providing a URI, as well as who owns it, and its ID.
After this, we pass all of those into an execution command in the shell, and we deploy it from our validator
account.
URI = {
"NFT info": "Some information about our NFT",
"image_URL": "your_url_here"
}
mint_msg = {
'mint': {
'token_id': '1-2-3',
'owner': 'fetch1wurz7uwmvchhc8x0yztc7220hxs9jxdjdsrqmn',
'token_uri': str(URI)
}
}
workshopNFT.execute(mint_msg, wallets['validator'])
N.B ensure that the URI is passed as a string.
After this, we should have a print message in the output log for our indexer that says [NFT Mint Handled]
.
This means our indexer has recognised the NFT mint event, as well as constructed and saved our NFT
entity.
By visiting http://localhost:3000/, we should be greeted with a GraphQL playground. Here we can query any entities that have been indexed.
In order to look specifically at our NFT entity, we can run this query, and we should see an output of all the entity information that we request in the query: id
, owner
and URI
.
query NFTs {
nFTs {
nodes {
id
owner
uri
}
}
}