Skip to content

Commit

Permalink
add graph post (celo-org#241)
Browse files Browse the repository at this point in the history
* add graph post

* add clarity around mappings

* Rename 2021-11-18-using-the-graph.md to index.md

* show blog page est reading time

* show more text in summary

* update post

* add blog to navbar

* add post

* update title

* update link

* add intro + tips
  • Loading branch information
critesjosh authored Nov 23, 2021
1 parent 683fac5 commit aa20aa8
Show file tree
Hide file tree
Showing 10 changed files with 316 additions and 9 deletions.
4 changes: 2 additions & 2 deletions blog/2021-11-08-contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ hide_table_of_contents: false

Contribute to Celo.

<!--truncate-->

## Open Source

Celo is an open source project and without community contributions from people like you Celo wouldn't exist. We welcome contributions to our [codebase](https://github.com/celo-org), [documentation](https://github.com/celo-org/docs), [translations](https://celo.crowdin.com/) and [blog](https://github.com/celo-org/docs/blog).
Expand All @@ -24,6 +22,8 @@ It can be difficult to find ways to meaningfully contribute to a new project, bu

Write about your experience as a member of the Celo community, whether you're a CELO owner or a project founder. Your experience and perspective is valuable and can help others.

<!--truncate-->

## Blog Ideas

Here are some topics that you could write about:
Expand Down
6 changes: 2 additions & 4 deletions blog/2021-11-15-code-playground.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ authors:
url: https://github.com/critesjosh
image_url: https://github.com/critesjosh.png
tags: [code playground]
image: https://i.imgur.com/mErPwqL.png
hide_table_of_contents: false
---

This post provides an introduction to the live code editor that is included as a feature in this blog. It allows you to see working examples of things like connecting to the Celo network with Metamask and initiating user transactions with the SDK.

<!--truncate-->

If you have any suggestions for examples that you'd like to see, or if you'd like to create one yourself and have it included in the blog, please reach out to me at [[email protected]](mailto:[email protected]) or on Discord at joshc#0001.

## Live coding
Expand All @@ -28,6 +25,7 @@ The code is rendered using [React Live](https://github.com/FormidableLabs/react-

:::

<!--truncate-->
### Hello World

Try it out:
Expand Down Expand Up @@ -57,4 +55,4 @@ function logger(){

Cool!

This is just a small preview into what code sharing and learning experiences we can build with this tool. Check out this post about [Connecting to Metamask](2021-11-15-connect-to-metamask.md) to learn more.
This is just a small preview into what code sharing and learning experiences we can build with this tool. Check out this post about [Connecting to Metamask](2021-11-16-connect-to-metamask.md) to learn more.
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,19 @@ authors:
url: https://github.com/critesjosh
image_url: https://github.com/critesjosh.png
tags: [code playground]
image: https://i.imgur.com/mErPwqL.png
hide_table_of_contents: false
---

Let's see how we can interact with Metamask from the code playground. We can connect to Metamask, switch networks, add tokens to the Metamask asset list and send them to other accounts.

<!--truncate-->

This post uses a live code editor. Check out [this post](2021-11-15-code-playground.md) to learn more about how it works.

:::tip

Make sure that you have have [Metamask installed](https://metamask.io) in your browser.

:::

## Connect to Metamask

The following example shows how to connect Metamask to this browser page.
Expand All @@ -44,6 +42,8 @@ function connect(){
}
```

<!--truncate-->

### Switch Networks

This example shows how you can prompt a user to connect to a specific Celo network. This component renders two buttons, one to connect to Celo mainnet and one to connect to the Alfajores testnet. If you try to connect to a network that you are already connected to, nothing happens.
Expand Down
62 changes: 62 additions & 0 deletions blog/2021-11-18-observable-intro/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Demos with ObservableHQ
description: Learn more about Observable notebooks and how they can be used in a blog
slug: observable-intro
authors: [josh]
tags: [observable]
image: https://logowik.com/content/uploads/images/the-graph-grt1266.jpg
hide_table_of_contents: false
---

## What is Observable?

[Observable HQ](https://observablehq.com/) is a Javascript notebook tool that makes it easy to share executable Javascript code right in the browser. This greatly reduces the friction around introducing and educating people about tools or features. Observable is designed primarily as a data visualization tool, but I have found it to be helpful for explaining and demonstrating concepts and behaviors for web3 as well.

For the official introduction to Observable, [check out the 5 minute introduction.](https://observablehq.com/@observablehq/five-minute-introduction?collection=@observablehq/introduction)

## Why I like it

### Easy to setup

First of all, there is nothing to download! This is a huge benefit when introducing developers to new technology. I can show off features and techniques for using new tech without requiring developers to have to download anything or set up an environment. This makes it easier to spark curiosity and inspire people to continue on their learning journey.

<!--truncate-->

### Code + Visualizations + Text

Observable supports Javascript, Markdown and HTML in cells. This means I can write executable Javascript surrounded by markdown that helps explain the context in which this code can be used and may be useful. The notebooks are also easy to embed into other contexts (like this blog).

Here is an example from a post on Merkle Trees. You can [view the full notebook here.](https://observablehq.com/@critesjosh/merkle-trees)

<iframe width="100%" height="643" frameborder="0" className="observable-notebook"
src="https://observablehq.com/embed/@critesjosh/merkle-trees?cells=chart%2Cp1%2Cvisualize_heading"></iframe>

### Executable Javascript

Observable allows anyone inspect the Javascript in the notebook and displays the results of the code execution. This is particularly useful to demo interactions with a connected web3 wallet or reviewing the structure of responses from API calls. Also, when code in one cell is updated, all other cells that use the code are referenced as well, kind of like hot reloading.

For example, in the [graph post](../2021-11-18-using-the-graph/index.md), I make a query to the Graph and the notebook shows a live response. Viewers can click through the notebook response to insepct the results.

[![the graph query](query.gif)](https://observablehq.com/@critesjosh/query-the-graph)

### Remix + Share

Viewers can edit the Javascript in the notebook and execute their own code to see the results. They can fork their changes and save them in their own notebook to be worked on later or to share with others.

I can import common node packages into a notebook and run them as I would in an application. This allows me to quickly test things and share them.

## What I don't like

Using Observable isn't great for everything--it has its limitations.

### Limited packages

While many npm packages work with observable, not all of them do. You may need to build packages to work specifically for Observable or import minified versions from a CDN. [This tool](https://observablehq.com/@observablehq/module-require-debugger) can help you figure out how to import packages that you want to use.

### Simple, specific actions

Observable is great for showing simple interactions with packages or creating visualizations, but is not well suited for demonstrating how to design or build an application. It is a unique environment where Javascript syntax may be different than what developers are used to, so it is useful for specific things.

### Iframe limitations

Observable notebooks are easiest to embed in other pages using an [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). This means the context of the notebook is limited by the same things as an iframe, which may or may not be a problem, depending on what you are trying to do. There are ways around this as well, you can link readers directly to your notebook or embed the notebook using a React component or vanilla Javascript. You can read more about embedding on the [Observable site here](https://observablehq.com/@observablehq/introduction-to-embedding).
Binary file added blog/2021-11-18-observable-intro/query.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added blog/2021-11-18-using-the-graph/dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
228 changes: 228 additions & 0 deletions blog/2021-11-18-using-the-graph/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
---
title: Using the Graph w/ Celo
description: Learn about what the Graph is and how to use it in your Celo DApp
slug: using-the-graph
authors: [josh]
tags: [The Graph, DApps]
image: https://logowik.com/content/uploads/images/the-graph-grt1266.jpg
hide_table_of_contents: false
---

import styles from '../styles.css'

[The Graph protocol](https://thegraph.com/) makes it easy to get historical blockchain data. This can be useful when you want to check a users history of using a specific token or interacting with a specific contract. It may also be useful when collecting data about the activity around a specific contract, or set of contracts. The Graph also makes this data easy to transform, organize and share across applications.

In this post I explore

- [What the Graph is](index.md#what-is-the-graph)
- [How to get started using the Graph with Celo](index.md#using-the-graph)
- [What a subgraph is and how to create one](index.md#initialize-your-subgraph)
- [How to deploy a subgraph to the Graph's hosted service](index.md#deploy-subgraph)
- [How to query a subgraph](index.md#query-the-subgraph)

## What is the Graph?

From the Graph website:

*The Graph is a decentralized protocol for indexing and querying data from blockchains, starting with Ethereum. It makes it possible to query data that is difficult to query directly.*

The problem that the Graph solves is that indexing blockchain data is actually very difficult. Additionally, the Graph makes it easy to get historical blockchain data without having to run your own archive node or paying to access an archive node through a node service provider, like [Quicknode](https://www.quicknode.com/chains/celo).

<!--truncate-->

## Using the Graph

I will be using [this GitHub repository](https://github.com/critesjosh/the-graph-hello-world) as a reference throughout this post. This repo contains a simple [HelloWorld contract](https://github.com/critesjosh/the-graph-hello-world/blob/master/HelloWorld.sol) that stores a string that can be updated.

`HelloWorld.sol`
```js
// HelloWorld.sol

// Learn more about Solidity here: https://solidity.readthedocs.io
pragma solidity >=0.5.0;

contract HelloWorld {

event NameUpdated(string newName, address updater);

// Define a string called name
string name;

// Declares a function called getName
// The 'public' label means the function can be called internally, by transactions or other contracts
// The 'view' label indicates that the function does not change the state of the contract
// The function returns a string, from the memory data location
function getName()
public
view
returns (string memory)
{
// Return the storage variable 'name'
return name;
}

// Declare a function called setName
// The function takes 1 parameter, a string, called newName, with the calldata data location in the Ethereum Virtual Machine
// The 'external' label means the function can only be called from an external source
function setName(string calldata newName)
external
{
emit NameUpdated(newName, msg.sender);
// Set the storage variable, name, to the value passed in as newName
name = newName;
}
}
```

The contract emits an event every time the storage sting is updated. Event handlers in the subgraph are triggered by contract events, so setting up a contract with events is required.

It is easiest to get started using the Graph hosted service, which supports queries on the Celo network.

:::tip

You can [learn more about the Graph's hosted service here](https://thegraph.com/docs/hostedservice/what-is-hosted-service).

:::

### Install the Graph CLI

The first step is to install the graph command line tool.

```bash
npm install -g @graphprotocol/graph-cli
```

or

```bash
yarn global add @graphprotocol/graph-cli
```

:::tip

Learn more about the `graph-cli` package [here](https://www.npmjs.com/package/@graphprotocol/graph-cli).

:::

### Initialize your Subgraph

*A subgraph defines which data The Graph will index from Ethereum, and how it will store it. Once deployed, it will form a part of a global graph of blockchain data.*

:::tip

[Read more about subgraphs on the Graph website.](https://thegraph.com/docs/developer/define-subgraph-hosted)

:::

In a new, empty project directory, run the following command in the terminal:

```bash
graph init --product hosted-service --from-contract 0xd2dC7E59971E934bF479B8eA86B9Ec1627B0F3D6 --network celo-alfajores --abi <FILE> critesjosh/Hello-World
```

The CLI tool will prompt you for some additional information. Use the "Hosted Service" for creating subgraphs that query contracts on the Celo network.

For the subgraph name, enter your GitHub username followed by the name of your project. In my case this is `critesjosh/Hello-World`.

The tool will ask you to specify a directory, network and contract address that you would like to query. I chose the default directory (Hello-World), the `celo-alfajores` network, the address of my deployed Solidity contract and the path to my [contract ABI](https://docs.soliditylang.org/en/latest/abi-spec.html).

The tool sets up my subgraph in the specified directory. Open `subgraph.yml` in the new subgraph project folder to see how it is configured. You can find more information about the [Subgraph Manifest file here](https://thegraph.com/docs/developer/create-subgraph-hosted#the-subgraph-manifest).

### Define the schema

The next step is to define your graphql schema in `schema.graphql` in the new project directory.

A graphql schema is like a dictionary that defines the types of entities to map from the data and how the entities are related. This is an important step to spend some time thinking about because this will define how your data is structured and linked. Here is [sushiswap's subgraph repo](https://github.com/sushiswap/sushiswap-subgraph) as a complex project reference.

For the simple HelloWorld contract that we are querying with this subgraph, I defined the schema like this:

```graphql
type Name @entity {
id: ID!
newName: String
updater: Bytes!
}
```

This will tell us the new name that is being stored in the contract, `newName`, and the account address that updated the name, `udpater`.

:::tip

[Read more about the Graph schemas here.](https://thegraph.com/docs/developer/create-subgraph-hosted#the-graphql-schema)

:::

### Define Mappings

Mappings are defined in `./src/mappings.ts` and transform the contract data (events) into the entities that are defined in `schema.graphql`. These mappings are written in a subset of Typescript.

In this example, there is only one event being indexed, so there is only one mapping.

```ts
import { NameUpdated } from '../generated/HelloWorld/HelloWorld'
import { Name } from '../generated/schema'

export function handleNameUpdated(event: NameUpdated): void {
let id = event.transaction.hash.toHex()
let name = Name.load(id)
if (name == null) {
name = new Name(id)
}
name.newName = event.params.newName
name.updater = event.params.updater
name.save()
}
```

This mapping sets the entity `id` as the transaction hash, the entity `newName` as the newName from the event parameter and the entity `updater` as the updater from the event parameter. The mapping will update an entity if one with a known `id` already exists, but since transaction hashes are unique, each event emitted from the contract will create a new entity.

:::tip

You can find more information about mappings on [the Graph website here](https://thegraph.com/docs/developer/create-subgraph-hosted#writing-mappings).

:::

Once the mapping is defined, you can generate the Graph AssemblyScript by running

```bash
graph codegen
```

"This will generate an AssemblyScript class for every smart contract in the ABI files mentioned in subgraph.yaml, allowing you to bind these contracts to specific addresses in the mappings and call read-only contract methods against the block being processed. It will also generate a class for every contract event to provide easy access to event parameters as well as the block and transaction the event originated from."

*--[The Graph codegen docs](https://thegraph.com/docs/developer/create-subgraph-hosted#code-generation)*

### Deploy Subgraph

To deploy the subgraph to the hosted service, you will need to create an account on [the Graph's hosted service site](https://thegraph.com/hosted-service).

From the [dashboard](https://thegraph.com/hosted-service/dashboard), you can find your Access Token for deploying the subgraph. Once you have that, you can authenticate with:

```bash
graph auth --product hosted-service <ACCESS_TOKEN>
```

Next, click the "Add Subgraph" button. Fill out the subgraph info with the appropriate information and deploy it with:

```bash
graph deploy --product hosted-service <GITHUB_USER>/<SUBGRAPH NAME>
```

Once your subgraph is deployed, you should be able to view it on the hosted service dashboard. You can view my [Hello World subgraph page here](https://thegraph.com/hosted-service/subgraph/critesjosh/hello-world).

![](dashboard.png)

Once the subgraph is deployed, the service will take some time to sync the events from the contract. Once it has been fully synced, you can run queries in the playground to test it out.

### Query the subgraph

You can learn more about [querying your subgraph from the hosted service here](https://thegraph.com/docs/hostedservice/query-hosted-service).

The following embedded code notebook from [Observable HQ](https://observablehq.com/) shows how to query the subgraph I deployed with basic Javascript. You can [view the notebook on Observable here](https://observablehq.com/@critesjosh/query-the-graph). I wrote a post that goes into more detail about Observable, you can [read it here](../2021-11-18-observable-intro/index.md).

You can inspect the JavaScript objects in the notebook by clicking on them. Try clicking on the `result` object. Click on the `names` array in the `data` object.

<iframe width="100%" height="500" frameborder="0" class="observable-notebook"
src="https://observablehq.com/embed/@critesjosh/query-the-graph?cell=*"></iframe>

You can see the entities that were defined in the `schema.graphql`, populated with event information like the `newName` and `updater` from each transaction!
5 changes: 5 additions & 0 deletions blog/authors.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
josh:
name: Josh Crites
title: Developer Relations, cLabs
url: https://github.com/critesjosh
image_url: https://github.com/critesjosh.png
3 changes: 3 additions & 0 deletions blog/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.observable-notebook {
background: white;
}
Loading

0 comments on commit aa20aa8

Please sign in to comment.