{"id":19200933,"url":"https://github.com/dabit3/building-a-subgraph-workshop","last_synced_at":"2025-11-17T15:24:29.113Z","repository":{"id":41514734,"uuid":"358999071","full_name":"dabit3/building-a-subgraph-workshop","owner":"dabit3","description":"In this workshop you'll learn how to build an NFT Subgraph using any smart contract or smart contracts.","archived":false,"fork":false,"pushed_at":"2022-04-18T21:19:55.000Z","size":26611,"stargazers_count":164,"open_issues_count":1,"forks_count":55,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-08-13T23:44:39.820Z","etag":null,"topics":["blockchain","ethereum","graph-protocol","nft","solidity"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dabit3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-17T22:58:25.000Z","updated_at":"2025-08-13T00:21:19.000Z","dependencies_parsed_at":"2022-08-10T02:35:24.588Z","dependency_job_id":null,"html_url":"https://github.com/dabit3/building-a-subgraph-workshop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dabit3/building-a-subgraph-workshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dabit3%2Fbuilding-a-subgraph-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dabit3%2Fbuilding-a-subgraph-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dabit3%2Fbuilding-a-subgraph-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dabit3%2Fbuilding-a-subgraph-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dabit3","download_url":"https://codeload.github.com/dabit3/building-a-subgraph-workshop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dabit3%2Fbuilding-a-subgraph-workshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271397956,"owners_count":24752640,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","ethereum","graph-protocol","nft","solidity"],"created_at":"2024-11-09T12:35:40.837Z","updated_at":"2025-11-17T15:24:29.058Z","avatar_url":"https://github.com/dabit3.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## The Graph - Subgraph Workshop\n\nLearn how to build a GraphQL API on top of the Ethereum blockchain to query data from [Foundation](https://foundation.app/).\n\n![Subgraph Workshop](images/header.png)\n\nIn this workshop you'll learn how to build and deploy a subgraph using the [Foundation NFT](https://foundation.app/) smart contract.\n\n### Prerequisites\n\nTo be successful in this workshop, you should have [Node.js](https://github.com/nvm-sh/nvm#node-version-manager---) installed on your machine.\n\n## Getting started\n\nTo get started, open [The Graph Hosted Service](https://thegraph.com/hosted-service/dashboard) and either sign in or create a new account.\n\n![Hosted studio dashboard](images/dash1.png)\n\nNext, go to the [dashboard](https://thegraph.com/hosted-service/dashboard) and click on __Add Subgraph__ to create a new subgraph.\n\n![Hosted studio dashboard](images/dash2.png)\n\nConfigure your subgraph with the following properties:\n\n- Subgraph Name - __Foundationsubgraph__\n- Subtitle - __A subgraph for querying NFTs__\n- Optional - Fill the description and GITHUB URL properties\n\n![Hosted studio dashboard](images/dash3.png)\n\nOnce the subgraph is created, we will initialize the subgraph locally using the Graph CLI.\n\n### Initializing a new subgraph using the Graph CLI\n\nNext, install the Graph CLI:\n\n```sh\nnpm install -g @graphprotocol/graph-cli\n\n# or\n\nyarn global add @graphprotocol/graph-cli\n```\n\nOnce the Graph CLI has been installed you can initialize a new subgraph with the Graph CLI `init` command.\n\nThere are two ways to initialize a new subgraph:\n\n1 - From an example subgraph (example command, do not run)\n\n```sh\ngraph init --from-example \u003cGITHUB_USERNAME\u003e/\u003cSUBGRAPH_NAME\u003e [\u003cDIRECTORY\u003e]\n```\n\n2 - From an existing smart contract (example command, do not run)\n\nIf you already have a smart contract deployed to Ethereum mainnet or one of the testnets, initializing a new subgraph from this contract is an easy way to get up and running.\n\n```sh\ngraph init --from-contract \u003cCONTRACT_ADDRESS\u003e \\\n  [--network \u003cETHEREUM_NETWORK\u003e] \\\n  [--abi \u003cFILE\u003e] \\\n  \u003cGITHUB_USER\u003e/\u003cSUBGRAPH_NAME\u003e [\u003cDIRECTORY\u003e]\n```\n\nIn our case we'll be starting with the [Foundation proxy contract](https://etherscan.io/address/0xc9fe4ffc4be41d93a1a7189975cd360504ee361a#code) so we can initialize from that contract address by passing in the contract address using the `--from-contract` flag.\n\n__Run the following command:__\n\n```sh\ngraph init --from-contract 0xc9fe4ffc4be41d93a1a7189975cd360504ee361a --protocol ethereum \\\n--network mainnet --contract-name Token --index-events\n\n? Product for which to initialize › hosted-service\n? Subgraph name › your-username/Foundationsubgraph\n? Directory to create the subgraph in › Foundationsubgraph\n? Ethereum network › Mainnet\n? Contract address › 0xc9fe4ffc4be41d93a1a7189975cd360504ee361a\n? Contract Name · Token\n```\n\nThis command will generate a basic subgraph based off of the contract address passed in as the argument to `--from-contract`. By using this contract address, the CLI will initialize a few things in your project to get you started (including fetching the `abis` and saving them in the __abis__ directory).\n\n\u003e By passing in `--index-events` the CLI will automatically populate some code for us both in __schema.graphql__ as well as __src/mapping.ts__ based on the events emitted from the contract.\n\nThe main configuration and definition for the subgraph lives in the __subgraph.yaml__ file. The subgraph codebase consists of a few files:\n\n- __subgraph.yaml__: a YAML file containing the subgraph manifest\n- __schema.graphql__: a GraphQL schema that defines what data is stored for your subgraph, and how to query it via GraphQL\n- __AssemblyScript Mappings__: AssemblyScript code that translates from the event data in Ethereum to the entities defined in your schema (e.g. mapping.ts in this tutorial)\n\nThe entries in __subgraph.yaml__ that we will be working with are:\n\n- `description` (optional): a human-readable description of what the subgraph is. This description is displayed by the Graph Explorer when the subgraph is deployed to the Hosted Service.\n- `repository` (optional): the URL of the repository where the subgraph manifest can be found. This is also displayed by the Graph Explorer.\n- `dataSources.source`: the address of the smart contract the subgraph sources, and the abi of the smart contract to use. The address is optional; omitting it allows to index matching events from all contracts.\n- `dataSources.source.startBlock` (optional): the number of the block that the data source starts indexing from. In most cases we suggest using the block in which the contract was created.\n- `dataSources.mapping.entities` : the entities that the data source writes to the store. The schema for each entity is defined in the the schema.graphql file.\n- `dataSources.mapping.abis`: one or more named ABI files for the source contract as well as any other smart contracts that you interact with from within the mappings.\n- `dataSources.mapping.eventHandlers`: lists the smart contract events this subgraph reacts to and the handlers in the mapping — __./src/mapping.ts__ in the example — that transform these events into entities in the store.\n\n### Defining the entities\n\nWith The Graph, you define entity types in __schema.graphql__, and Graph Node will generate top level fields for querying single instances and collections of that entity type. Each type that should be an entity is required to be annotated with an `@entity` directive.\n\nThe entities / data we will be indexing are the `Token` and `User`. This way we can index the Tokens created by the users as well as the users themselves.\n\nTo do this, update __schema.graphql__ with the following code:\n\n```graphql\ntype Token @entity {\n  id: ID!\n  tokenID: BigInt!\n  contentURI: String\n  tokenIPFSPath: String\n  name: String!\n  createdAtTimestamp: BigInt!\n  creator: User!\n  owner: User!\n}\n\ntype User @entity {\n  id: ID!\n  tokens: [Token!]! @derivedFrom(field: \"owner\")\n  created: [Token!]! @derivedFrom(field: \"creator\")\n}\n```\n\n### On Relationships via `@derivedFrom` (from the docs):\n\nReverse lookups can be defined on an entity through the `@derivedFrom` field. This creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API. Rather, it is derived from the relationship defined on the other entity. For such relationships, it rarely makes sense to store both sides of the relationship, and both indexing and query performance will be better when only one side is stored and the other is derived.\n\nFor one-to-many relationships, the relationship should always be stored on the 'one' side, and the 'many' side should always be derived. Storing the relationship this way, rather than storing an array of entities on the 'many' side, will result in dramatically better performance for both indexing and querying the subgraph. In general, storing arrays of entities should be avoided as much as is practical.\n\nNow that we have created the GraphQL schema for our app, we can generate the entities locally to start using in the `mappings` created by the CLI:\n\n```sh\ngraph codegen\n```\n\nIn order to make working smart contracts, events and entities easy and type-safe, the Graph CLI generates AssemblyScript types from a combination of the subgraph's GraphQL schema and the contract ABIs included in the data sources.\n\n## Updating the subgraph with the entities and mappings\n\nNow we can configure the __subgraph.yaml__ to use the entities that we have just created and configure their mappings.\n\nTo do so, first update the `dataSources.mapping.entities` field with the `User` and `Token` entities:\n\n```yaml\nentities:\n  - Token\n  - User\n```\n\nNext, update the `dataSources.mapping.eventHandlers` to include only the following three event handlers:\n\n```yaml\n- event: TokenIPFSPathUpdated(indexed uint256,indexed string,string)\n  handler: handleTokenIPFSPathUpdated\n- event: Transfer(indexed address,indexed address,indexed uint256)\n  handler: handleTransfer\n```\n\nFinally, update the configuration to add the startBlock and change the contract `address` to the [main contract](https://etherscan.io/address/0x3B3ee1931Dc30C1957379FAc9aba94D1C48a5405) address:\n\n```yaml\nsource:\n  address: \"0x3B3ee1931Dc30C1957379FAc9aba94D1C48a5405\"\n  abi: Token\n  startBlock: 11565020\n```\n\n## Assemblyscript mappings\n\nNext, open __src/mappings.ts__ to write the mappings that we defined in our subgraph subgraph `eventHandlers`.\n\nUpdate the file with the following code:\n\n```typescript\nimport {\n  TokenIPFSPathUpdated as TokenIPFSPathUpdatedEvent,\n  Transfer as TransferEvent,\n  Token as TokenContract,\n} from \"../generated/Token/Token\"\n\nimport {\n  Token, User\n} from '../generated/schema'\n\nexport function handleTransfer(event: TransferEvent): void {\n  let token = Token.load(event.params.tokenId.toString());\n  if (!token) {\n    token = new Token(event.params.tokenId.toString());\n    token.creator = event.params.to.toHexString();\n    token.tokenID = event.params.tokenId;\n  \n    let tokenContract = TokenContract.bind(event.address);\n    token.contentURI = tokenContract.tokenURI(event.params.tokenId);\n    token.tokenIPFSPath = tokenContract.getTokenIPFSPath(event.params.tokenId);\n    token.name = tokenContract.name();\n    token.createdAtTimestamp = event.block.timestamp;\n  }\n  token.owner = event.params.to.toHexString();\n  token.save();\n    \n  let user = User.load(event.params.to.toHexString());\n  if (!user) {\n    user = new User(event.params.to.toHexString());\n    user.save();\n  }\n}\n\nexport function handleTokenURIUpdated(event: TokenIPFSPathUpdatedEvent): void {\n  let token = Token.load(event.params.tokenId.toString());\n  if (!token) return\n  token.tokenIPFSPath = event.params.tokenIPFSPath;\n  token.save();\n}\n```\n\nThese mappings will handle events for when a new token is created, transferred, or updated. When these events fire, the mappings will save the data into the subgraph.\n\n### Running a build\n\nNext, let's run a build to make sure that everything is configured properly. To do so, run the `build` command:\n\n```sh\ngraph build\n```\n\nIf the build is successful, you should see a new __build__ folder generated in your root directory.\n\n## Deploying the subgraph\n\nTo deploy, we can run the `deploy` command using the Graph CLI. To deploy, you will first need to copy the __Access token__ for your account, available in the [Graph Explorer](https://thegraph.com/explorer/dashboard):\n\n![Graph Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/820lwqh8yo3iyu7fsbhj.jpg)\n\nNext, run the following command:\n\n```sh\n$ graph auth\n✔ Product for which to initialize · hosted-service\n✔ Deploy key · ********************************\n\nyarn deploy\n```\n\nOnce the subgraph is deployed, you should see it show up in your dashboard:\n\n![Graph Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q548jeq4kuhgddrjv0dv.jpg)\n\nWhen you click on the subgraph, it should open the Graph explorer:\n\n![The Foundation Subgraph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9qremconu1io72z3g6pa.png)\n\n## Querying for data\n\nNow that we are in the dashboard, we should be able to start querying for data. Run the following query to get a list of tokens and their metadata:\n\n```graphql\n{\n  tokens {\n    id\n    tokenID\n    contentURI\n    tokenIPFSPath\n  }\n}\n```\n\nWe can also configure the order direction:\n\n```graphql\n{\n  tokens(\n    orderBy:id,\n    orderDirection: desc\n  ) {\n    id\n    tokenID\n    contentURI\n    tokenIPFSPath\n  }\n}\n```\n\nOr choose to skip forward a certain number of results to implement some basic pagination:\n\n```graphql\n{\n  tokens(\n    skip: 100,\n    orderBy:id,\n    orderDirection: desc\n  ) {\n    id\n    tokenID\n    contentURI\n    tokenIPFSPath\n  }\n}\n```\n\nOr query for users and their associated content:\n\n```graphql\n{\n  users {\n    id\n    tokens {\n      id\n      contentURI\n    }\n  }\n}\n```\n\nWe can also query by timestamp to view the most recently created NFTS:\n\n```graphql\n{\n  tokens(\n    orderBy: createdAtTimestamp,\n    orderDirection: desc\n  ) {\n    id\n    tokenID\n    contentURI\n  }\n}\n```\n\n\u003e The codebase for this project is located [here](https://github.com/dabit3/building-a-subgraph-workshop/tree/main/Foundationsubgraph)\n\n## Next steps\n\nIf you are interested in learning more about Web3, building Dapps, or building subgraphs, check out the following resources:\n\nThe Graph on Twitter - [@graphprotocol](https://twitter.com/graphprotocol)\n\n[The Complete Guide to Full Stack Ethereum Development](https://dev.to/dabit3/the-complete-guide-to-full-stack-ethereum-development-3j13)\n\n[The Graph Discord](thegraph.com/discord)\n\n[Solidity Docs](https://docs.soliditylang.org/)\n\n[Ethereum Developer Documentation](https://ethereum.org/en/developers/docs/)\n\nAustin Griffith on Twitter [@austingriffith](https://twitter.com/austingriffith) \u0026 [Scaffold Eth](https://github.com/austintgriffith/scaffold-eth)\n\n[Crypto Zombies](https://cryptozombies.io/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdabit3%2Fbuilding-a-subgraph-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdabit3%2Fbuilding-a-subgraph-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdabit3%2Fbuilding-a-subgraph-workshop/lists"}