Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cookbook-Enums #798

Merged
merged 9 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion website/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
1 change: 1 addition & 0 deletions website/pages/en/cookbook/_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export default {
derivedfrom: 'Subgraph Best Practice 2: Manage Arrays with @derivedFrom',
'immutable-entities-bytes-as-ids': 'Subgraph Best Practice 3: Using Immutable Entities and Bytes as IDs',
'avoid-eth-calls': 'Subgraph Best Practice 4: Avoid eth_calls',
enums: 'Categorizing NFT Marketplaces Using Enums',
idalithb marked this conversation as resolved.
Show resolved Hide resolved
idalithb marked this conversation as resolved.
Show resolved Hide resolved
}
274 changes: 274 additions & 0 deletions website/pages/en/cookbook/enums.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
---
title: Categorize NFT Marketplaces Using Enums
---

Use Enums to make your code cleaner and less error-prone. Here's a full example of using Enums on NFT marketplaces.

## What are Enums?

Enums, or enumeration types, are a specific data type that allows you to define a set of specific, allowed values.

### Example of Enums in Your Schema

If you're building a subgraph to track the ownership history of tokens on a marketplace, each token might go through different ownerships, such as `OriginalOwner`, `SecondOwner`, and `ThirdOwner`. By using enums, you can define these specific ownerships, ensuring only predefined values are assigned.

You can define enums in your schema, and once defined, you can use the string representation of the enum values to set an enum field on an entity.

Here's what an enum definition might look like in your schema, based on the example above:

```graphql
enum TokenStatus {
OriginalOwner
SecondOwner
ThirdOwner
}
```

This means that when you use the `TokenStatus` type in your schema, you expect it to be exactly one of predefined values: `OriginalOwner`, `SecondOwner`, or `ThirdOwner`, ensuring consistency and validity.

To learn more about enums, check out [Creating a Subgraph](/developing/creating-a-subgraph/#enums) and [GraphQL documentation](https://graphql.org/learn/schema/#enumeration-types).

## Benefits of Using Enums
idalithb marked this conversation as resolved.
Show resolved Hide resolved

- **Clarity:** Enums provide meaningful names for values, making data easier to understand.
- **Validation:** Enums enforce strict value definitions, preventing invalid data entries.
- **Maintainability:** When you need to change or add new categories, enums allow you to do this in a focused manner.
idalithb marked this conversation as resolved.
Show resolved Hide resolved

### Without Enums

If you choose to define the type as a string instead of using an Enum, your code might look like this:

```graphql
type Token @entity {
id: ID!
tokenId: BigInt!
owner: Bytes! # Owner of the token
tokenStatus: String! # String field to track token status
timestamp: BigInt!
}
```

In this schema, `TokenStatus` is a simple string with no specific, allowed values.

#### Why is this a problem?

- There's no restriction of `TokenStatus` values, so any string can be accidentally assigned. This makes it hard to ensure that only valid statuses like `OriginalOwner`, `SecondOwner`, or `ThirdOwner` are set.
- It's easy to make typos such as `Orgnalowner` instead of `OriginalOwner`, making the data and potential queries unreliable.

### With Enums

Instead of assigning free-form strings, you can define an enum for `TokenStatus` with specific values: `OriginalOwner`, `SecondOwner`, or `ThirdOwner`. Using an enum ensures only allowed values are used.

Enums provide type safety, minimize typo risks, and ensure consistent and reliable results.

## Defining Enums for NFT Marketplaces

> Note: The following guide uses the CryptoCoven NFT smart contract.

To define enums for the various marketplaces where NFTs are traded, use the following in your subgraph schema:

```gql
# Enum for Marketplaces that the CryptoCoven contract interacted with(likely a Trade/Mint)
enum Marketplace {
OpenSeaV1 # Represents when a CryptoCoven NFT is traded on the marketplace
OpenSeaV2 # Represents when a CryptoCoven NFT is traded on the OpenSeaV2 marketplace
SeaPort # Represents when a CryptoCoven NFT is traded on the SeaPort marketplace
LooksRare # Represents when a CryptoCoven NFT is traded on the LookRare marketplace
idalithb marked this conversation as resolved.
Show resolved Hide resolved
# ...and other marketplaces
}
```

## Using Enums for NFT Marketplaces

Once defined, enums can be used throughout your subgraph to categorize transactions or events.

For example, when logging NFT sales, you can specify the marketplace involved in the trade using the enum.

### Implementing a Function for NFT Marketplaces

Here's how you can implement a function to retrieve the marketplace name from the enum as a string:

```ts
export function getMarketplaceName(marketplace: Marketplace): string {
// Using if-else statements to map the enum value to a string
if (marketplace === Marketplace.OpenSeaV1) {
return 'OpenSeaV1' // If the marketplace is OpenSea, return its string representation
} else if (marketplace === Marketplace.OpenSeaV2) {
return 'OpenSeaV2'
} else if (marketplace === Marketplace.SeaPort) {
return 'SeaPort' // If the marketplace is SeaPort, return its string representation
} else if (marketplace === Marketplace.LooksRare) {
idalithb marked this conversation as resolved.
Show resolved Hide resolved
return 'LooksRare' // If the marketplace is LooksRare, return its string representation
// ... and other market places
}
}
```

## Best Practices for Using Enums

- **Consistent Naming:** Use clear, descriptive names for enum values to improve readability.
- **Centralized Management:** Keep enums in a single file for consistency. This makes enums easier to update and ensures they are the single source of truth.
- **Documentation:** Add comments to enum to clarify their purpose and usage.

## Using Enums in Queries

Enums in queries help you improve data quality and make your results easier to interpret. They function as filters and response elements, ensuring consistency and reducing errors in marketplace values.

**Specifics**

- **Filtering with Enums:** Enums provide clear filters, allowing you to confidently include or exclude specific marketplaces.
- **Enums in Responses:** Enums guarantee that only recognized marketplace names are returned, making the results standardized and accurate.

### Sample Queries

#### Query 1: Account With The Highest NFT Marketplace Interactions

This query does the following:

- It finds the account with the highest unique NFT marketplace interactions, which is great for analyzing cross-marketplace activity.
- The marketplaces field uses the marketplace enum, ensuring consistent and validated marketplace values in the response.

```gql
{
accounts(first: 1, orderBy: uniqueMarketplacesCount, orderDirection: desc) {
id
sendCount
receiveCount
totalSpent
uniqueMarketplacesCount
marketplaces {
marketplace # This field returns the enum value representing the marketplace
}
}
}
```

#### Returns

This response provides account details and a list of unique marketplace interactions with enum values for standardized clarity:

```gql
{
"data": {
"accounts": [
{
"id": "0xb3abc96cb9a61576c03c955d75b703a890a14aa0",
"sendCount": "44",
"receiveCount": "44",
"totalSpent": "1197500000000000000",
"uniqueMarketplacesCount": "7",
"marketplaces": [
{
"marketplace": "OpenSeaV1"
},
{
"marketplace": "OpenSeaV2"
},
{
"marketplace": "GenieSwap"
},
{
"marketplace": "CryptoCoven"
},
{
"marketplace": "Unknown"
},
{
"marketplace": "LooksRare"
},
{
"marketplace": "NFTX"
}
]
}
]
}
}
```

#### Query 2: Most Active Marketplace for CryptoCoven transactions

This query does the following:

- It identifies the marketplace with the highest volume of CryptoCoven transactions.
- It uses the marketplace enum to ensure that only valid marketplace types appear in the response, adding reliability and consistency to your data.

```gql
{
marketplaceInteractions(first: 1, orderBy: transactionCount, orderDirection: desc) {
marketplace
transactionCount
}
}
```

#### Result 2

The expected response includes the marketplace and the corresponding transaction count, using the enum to indicate the marketplace type:

```gql
{
"data": {
"marketplaceInteractions": [
{
"marketplace": "Unknown",
"transactionCount": "222"
}
]
}
}
```

#### Query 3: Marketplace Interactions with High Transaction Counts

This query does the following:

- It retrieves the top four marketplaces with over 100 transactions, excluding "Unknown" marketplaces.
- It uses enums as filters to ensure that only valid marketplace types are included, increasing accuracy.

```gql
{
marketplaceInteractions(
first: 4
orderBy: transactionCount
orderDirection: desc
where: { transactionCount_gt: "100", marketplace_not: "Unknown" }
) {
marketplace
transactionCount
}
}
```

#### Result 3

Expected output includes the marketplaces that meet the criteria, each represented by an enum value:

```gql
{
"data": {
"marketplaceInteractions": [
{
"marketplace": "NFTX",
"transactionCount": "201"
},
{
"marketplace": "OpenSeaV1",
"transactionCount": "148"
},
{
"marketplace": "CryptoCoven",
"transactionCount": "117"
},
{
"marketplace": "OpenSeaV1",
"transactionCount": "111"
}
]
}
}
```

## Additional Resources

For additional information, check out this guide's [repo](https://github.com/chidubemokeke/Subgraph-Tutorial-Enums).
Loading