Skip to content

Commit

Permalink
Introduce prefix for quantitative fields
Browse files Browse the repository at this point in the history
  • Loading branch information
this-username-is-taken committed Apr 18, 2022
1 parent 9bd077c commit 6a20d52
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 53 deletions.
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
# Subgraphs

This repo contains subgraphs defined using a set of standardized schemas. These subgraphs are used to extract raw blockchain data and transform them into meaningful metrics, for products and analytics. Our goal is to build a subgraph for every DeFi protocol in the space.

## Contribution Guidelines

- Decide which protocol you want to build a subgraph for
- Fork this repository
- Add a folder under `subgraphs` with the name of the protocol you want to work on
- Copy over the corresponding schema from the root folder. For example, if you are working on a yield aggregator, you should copy over `schema-yield.graphql` to your folder and rename it to `schema.graphql`. Note `schema-common.graphql` is used for schema design and reference, and should never be used for implementation
- Decide which protocol you want to build a subgraph for.
- Fork this repository.
- Add a folder under `subgraphs` with the name of the protocol you want to work on.
- Copy over the corresponding schema from the root folder. For example, if you are working on a yield aggregator, you should copy over `schema-yield.graphql` to your folder and rename it to `schema.graphql`. Note `schema-common.graphql` is used for schema design and reference, and should never be used for implementation.
- Build the subgraph within that folder. Feel free to use the [reference subgraph](./subgraphs/_reference_/) as a reference.
- Submit a PR (pull request) to this repo after you are done. Make sure you submit your PR as a draft if it's a work-in-progress.

## Recommended Development Workflow

- Start with understanding the protocol. An easy start could be interacting with the protocol UI on testnets, check transaction details on Etherscan and pay attention to key events that are emitted
- Go over the smart contracts. Identify the ones that we need to pull data from
- Usually each protocol has a factory contract that's responsible for tracking other contracts (e.g. Uniswap's Factory contract, Aave's Lending Pool Registry, Yearn's Registry)
- Also a pool/vault contract that's responsible for pool level bookkeeping and transactions (e.g. Uniswap's Pair contract, Yearn's Vault contract, Aave's Lending Pool contract)
- Go over the schema and think about what data are needed from smart contract events/calls to map to the fields in each entity
- It's easiest to start with more granular entities and build up to aggregated data
- For example, usually it's easier to start writing mappings for transactions and usage metrics
- Go over the documents in the `docs` folder. That should answer lots of questions you may have
- Implement the mappings, deploy and test your data using either Hosted Service or The Graph Studio
- For metrics calculation (e.g. revenue, fees, TVL), please refer to the `README.md` in the protocol's subgraph folder for methodology. There is also a broader explanation of how different fields are defined in the schema in `docs/Schema.md`. Feel free to reach out to me if anything isn't clear
- Start with understanding the protocol. An easy start could be interacting with the protocol UI on testnets, check transaction details on Etherscan and pay attention to key events that are emitted.
- Go over the smart contracts. Identify the ones that we need to pull data from.
- Usually each protocol has a factory contract that's responsible for tracking other contracts (e.g. Uniswap's Factory contract, Aave's Lending Pool Registry, Yearn's Registry).
- Also a pool/vault contract that's responsible for pool level bookkeeping and transactions (e.g. Uniswap's Pair contract, Yearn's Vault contract, Aave's Lending Pool contract).
- Go over the schema and think about what data are needed from smart contract events/calls to map to the fields in each entity.
- It's easiest to start with more granular entities and build up to aggregated data.
- For example, usually it's easier to start writing mappings for transactions and usage metrics.
- Go over the documents in the `docs` folder. That should answer lots of questions you may have.
- Implement the mappings, deploy and test your data using either Hosted Service or The Graph Studio.
- For metrics calculation (e.g. revenue, fees, TVL), please refer to the `README.md` in the protocol's subgraph folder for methodology. There is also a broader explanation of how different fields are defined in the schema in `docs/Schema.md`. Feel free to reach out to me if anything isn't clear.
- Verify your subgraph against other sources and include specific links to these sources in the README. Below are some common sources:
- Project's official analytics dashboard
- [DeFi Llama](https://defillama.com/) (for TVL)
Expand Down
41 changes: 40 additions & 1 deletion docs/Schema.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
# Schema Definition

All subgraphs follow a set of standardized schemas. This standardization brings some important benefits:

**It makes it extremely easy for people to consume the subgraph data.**

- Every protocol has slightly different terminology and definition, making it difficult for people to make sense of their data.
- You will only need a single set of queries / pipeline to pull data from all supported protocols.
- All data are normalized in the same way, which saves you a huge amount of work.

**It makes it easy for developers to contribute.**

- Defining a subgraph schema from scratch can be a daunting task as there are many edge cases and nuances to consider. Our schema is battle-tested, making it a great starting point for any subgraph.
- We have a large set of subgraph implementations for you to refer to, and a wealth of tribal knowledge tracked in PRs and comments.
- We have a set of common libraries that you can leverage. Some of them took weeks to implement.
- We have great tooling you can use to validate your subgraph.

***

## Naming Conventions

- Enum values should be in all caps.
- Common types:
- hash/address: `String`
- block height: `BigInt`
- timestamp: unix timestamp in `BigInt`
- token amount: All token amounts should be BigInt to preserve precision (i.e. in wei)
- dollar amount: All USD amounts (including prices) should be BigDecimal
- Certain prefixes may be used to indicate a particular type of value:
- *current*: indicates this is a spot balance. In other words, the value as of this point in time. E.g. `currentTvlUSD` means the total TVL of the protocol/pool as of now.
- *cumulative*: sum of all historical data from day 1 up to this point. E.g. `cumulativeDepositUSD` means all deposits has ever been made to this protocol/pool.
- *daily*: this only applies to snapshots and represents the sum of the snapshot interval (i.e. daily aggregate). E.g. `dailyActiveUsers` means all unique in the past day.
- Use plurals when referring to multiple items, ususally stored as an array (e.g. tokens, balances).

### Quantitative Data

- There are 3 ways in which quantitative data are stored and fetched:
1. Real-time: you can get real-time data by querying on specific entities. For example, get `currentTvlUSD` from a `Pool`.
2. Point-in-time: you can get point-in-time (including historical) data on specific entities using [time-travel queries](https://thegraph.com/docs/en/developer/graphql-api/#time-travel-queries).
3. Time-series: the best way to get time-series data is by querying for snapshots. For example, get `currentTvlUSD` from `PoolDailySnapshot`.

## Versioning

Every subgraph has a embedded versioning system in the `Protocol` entity/interface. We use 3 separate fields to version different aspects of the subgraphs for different stakeholders.
Expand Down Expand Up @@ -123,7 +162,7 @@ There are situations where you may want to have additional entities in your sche
- Entities to save internal states of your subgraph for aggregation (e.g. counting)
- Entities to cached contract call result (e.g. prices)

In general, feel free to add extra entities that tracks the internal state of the subgraph as you see fit. Make sure you prefix these entities with an underscore (e.g. `_User`) to differentiate it from entities in the common schema.
In general, feel free to add extra entities that tracks the internal state of the subgraph as you see fit. Make sure you prefix these entities with an underscore (e.g. `_User`) to differentiate it from entities in the common schema. The same applies to extra fields within existing entities.

Make sure these changes are **strictly** additive. If you need to **modify** existing entities, please let me know and we can go through it together.

Expand Down
85 changes: 47 additions & 38 deletions schema-dex-amm.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Subgraph Schema: DEX AMM
# Version: 1.1.3
# Version: 1.2.0
# See https://github.com/messari/subgraphs/blob/master/docs/Schema.md for details

enum Network {
ARBITRUM
Expand Down Expand Up @@ -81,13 +82,14 @@ interface Protocol {

type: ProtocolType!

" # of total/cumulative unique users "
totalUniqueUsers: Int!
" Current TVL (Total Value Locked) of the entire protocol "
currentTvlUSD: BigDecimal!

totalValueLockedUSD: BigDecimal!
" # of cumulative unique users "
cumulativeUniqueUsers: Int!

" Total volume in USD "
totalVolumeUSD: BigDecimal!
" All historical volume in USD "
cumulativeVolumeUSD: BigDecimal!

usageMetrics: [UsageMetricsDailySnapshot!]! @derivedFrom(field: "protocol")

Expand All @@ -104,11 +106,11 @@ type UsageMetricsDailySnapshot @entity {

protocol: DexAmmProtocol!

" # of unique daily active users "
activeUsers: Int!
" # of cumulative unique users "
cumulativeUniqueUsers: Int!

" # of total/cumulative unique users "
totalUniqueUsers: Int!
" # of unique daily active users "
dailyActiveUsers: Int!

" Total number of transaction occurred in a day. Transactions include all entities that implement the Event interface. "
dailyTransactionCount: Int!
Expand All @@ -126,22 +128,23 @@ type FinancialsDailySnapshot @entity {

protocol: DexAmmProtocol!

totalValueLockedUSD: BigDecimal!
" Current TVL (Total Value Locked) of the entire protocol "
currentTvlUSD: BigDecimal!

" Only relevant for protocols with PCV. "
protocolControlledValueUSD: BigDecimal
" Current PCV (Protocol Controlled Value). Only relevant for protocols with PCV. "
currentPcvUSD: BigDecimal

" Total volume in USD "
totalVolumeUSD: BigDecimal!
" All historical volume in USD "
cumulativeVolumeUSD: BigDecimal!

" Revenue claimed by suppliers to the protocol. LPs on DEXs (e.g. 0.25% of the swap fee in Sushiswap). Depositors on Lending Protocols. NFT sellers on OpenSea. "
supplySideRevenueUSD: BigDecimal!
cumulativeSupplySideRevenueUSD: BigDecimal!

" Gross revenue for the protocol (revenue claimed by protocol). Examples: AMM protocol fee (Sushi’s 0.05%). OpenSea 10% sell fee. "
protocolSideRevenueUSD: BigDecimal!
cumulativeProtocolSideRevenueUSD: BigDecimal!

" Total revenue accrued by the protocol. e.g. 0.30% of swap fee in Sushiswap, all yield generated by Yearn. "
totalRevenueUSD: BigDecimal!
cumulativeTotalRevenueUSD: BigDecimal!

" Block number of this snapshot "
blockNumber: BigInt!
Expand Down Expand Up @@ -173,13 +176,14 @@ type DexAmmProtocol implements Protocol @entity {

type: ProtocolType!

" # of total/cumulative unique users "
totalUniqueUsers: Int!
" Current TVL (Total Value Locked) of the entire protocol "
currentTvlUSD: BigDecimal!

totalValueLockedUSD: BigDecimal!
" # of cumulative unique users "
cumulativeUniqueUsers: Int!

" Total volume in USD "
totalVolumeUSD: BigDecimal!
" All historical volume in USD "
cumulativeVolumeUSD: BigDecimal!

usageMetrics: [UsageMetricsDailySnapshot!]! @derivedFrom(field: "protocol")

Expand Down Expand Up @@ -248,10 +252,11 @@ type LiquidityPool @entity {

##### Quantitative Data #####

totalValueLockedUSD: BigDecimal!
" Current TVL (Total Value Locked) of this pool "
currentTvlUSD: BigDecimal!

" Total swap volume in USD "
totalVolumeUSD: BigDecimal!
" All historical volume occurred in this pool in USD "
cumulativeVolumeUSD: BigDecimal!

" Amount of input tokens in the pool. The ordering should be the same as the pool's `inputTokens` field. "
inputTokenBalances: [BigInt!]!
Expand All @@ -263,13 +268,13 @@ type LiquidityPool @entity {
outputTokenPriceUSD: BigDecimal

" Total supply of output tokens that are staked (usually in the MasterChef contract). Used to calculate reward APY. "
stakedOutputTokenAmount: BigInt
currentStakedOutputTokenAmount: BigInt

" Total amount of reward token emissions in a day, in token's native amount "
rewardTokenEmissionsAmount: [BigInt!]
" Per-block reward token emission normalized to a day, in token's native amount. This should be ideally calculated as the theoretical amount instead of the realized amount. "
currentRewardTokenEmissionsAmount: [BigInt!]

" Total amount of reward token emissions in a day, normalized to USD "
rewardTokenEmissionsUSD: [BigDecimal!]
" Per-block reward token emission normalized to a day, in USD value. This should be ideally calculated as the theoretical amount instead of the realized amount. "
currentRewardTokenEmissionsUSD: [BigDecimal!]

" Creation timestamp "
createdTimestamp: BigInt!
Expand Down Expand Up @@ -315,10 +320,11 @@ type PoolDailySnapshot @entity {
" The pool this snapshot belongs to "
pool: LiquidityPool!

totalValueLockedUSD: BigDecimal!
" Current TVL (Total Value Locked) of this pool "
currentTvlUSD: BigDecimal!

" Total volume in USD "
totalVolumeUSD: BigDecimal!
" All historical volume occurred in this pool in USD "
cumulativeVolumeUSD: BigDecimal!

" Amount of input tokens in the pool. The ordering should be the same as the pool's `inputTokens` field. "
inputTokenBalances: [BigInt!]!
Expand All @@ -328,12 +334,15 @@ type PoolDailySnapshot @entity {

" Price per share of output token in USD "
outputTokenPriceUSD: BigDecimal

" Total supply of output tokens that are staked (usually in the MasterChef contract). Used to calculate reward APY. "
currentStakedOutputTokenAmount: BigInt

" Total amount of reward token emissions in a day, in token's native amount "
rewardTokenEmissionsAmount: [BigInt!]
" Per-block reward token emission normalized to a day, in token's native amount. This should be ideally calculated as the theoretical amount instead of the realized amount. "
currentRewardTokenEmissionsAmount: [BigInt!]

" Total amount of reward token emissions in a day, normalized to USD "
rewardTokenEmissionsUSD: [BigDecimal!]
" Per-block reward token emission normalized to a day, in USD value. This should be ideally calculated as the theoretical amount instead of the realized amount. "
currentRewardTokenEmissionsUSD: [BigDecimal!]

" Block number of this snapshot "
blockNumber: BigInt!
Expand Down
1 change: 1 addition & 0 deletions schema-generic.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Subgraph Schema: Generic
# Version: 1.1.0
# See https://github.com/messari/subgraphs/blob/master/docs/Schema.md for details

enum Network {
ARBITRUM
Expand Down
1 change: 1 addition & 0 deletions schema-lending.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Subgraph Schema: Lending Protocol
# Version: 1.1.0
# See https://github.com/messari/subgraphs/blob/master/docs/Schema.md for details

enum Network {
ARBITRUM
Expand Down
1 change: 1 addition & 0 deletions schema-yield.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Subgraph Schema: Yield Aggregator
# Version: 1.1.1
# See https://github.com/messari/subgraphs/blob/master/docs/Schema.md for details

enum Network {
ARBITRUM
Expand Down

0 comments on commit 6a20d52

Please sign in to comment.