0x Protocol community subgraph. These subgraphs contain comprehensive data on the 0x protocol on all networks.
- 0x Protocol Community Subgraph
Blockchain Network | The Graph Hosted | The Graph Decentralized | Alchemy |
---|---|---|---|
Ethereum Mainnet | Mainnet Hosted | Mainnet Decentralized | Alchemy |
Optimism | Optimism Hosted | Optimism Decentralized | Alchemy |
Arbitrum | Arbitrum Hosted | Arbitrum Decentralized | Alchemy |
Base | Base Hosted | Base Decentralized | Alchemy |
Polygon | Polygon Hosted | Polygon Decentralized | Alchemy |
BNB | BNB Hosted | BNB Decentralized | Alchemy |
Avalanche | Avalanche Hosted | Avalanche Decentralized | Not supported |
Fantom | Fantom Hosted | Fantom Decentralized | Not supported |
Celo | Celo Hosted | Celo Decentralized | Not supported |
- Each element in the schema is well documented. You can view the docs directly in the schema file, or The Graph also displays these in their graphql interface.
- We provided example queries to help people get started. These can also be seen in The Graphs playground.
- As part of validation, we wrote some Jupyter notebooks which query the subgraphs in Python. In the historical notebook we plot a lot of historical data, which can be useful to help visualize some of the subgraph the data.
- One limitation of subgraphs is the inability to track native asset transfers (ex. ETH) in internal calls. This means we cannot accurately do accounting of complex swaps which use native assets during or at the end of the swap.
- We try our best to infer the sender, filler and recipient for each fill when they are not provided by an event, but sometimes it is not possible. This occurs for example, in cases where:
- An ERC20 doesn't emit Transfer events, or the event doesn't not conform to the ERC20 standard
- During LiquidityProviderSwap when the input token is the native asset.
- During BridgeFills when the input token is ETH, and the output token gets minted (for example, ETH -> cETHv3)
- Due the the limitations of internal call native asset tracking mentioned above, we do not try to infer and assemble full swaps. Instead we provide all the fills for a transaction, and all erc20 transfer which happen within. It is possible for the querier to assemble the entire swap using this data and a 3rd party source to fill in the native transfer blanks.
- Derived prices:
- Derived native asset (ex. ETH) prices are computed whenever an ERC20 fill occurs. For each token involved in the fill, the native asset price of the token is derived by looking at all token pairs with a whitelisted token (which can be assumed to have a reliable prices). Of these pairs, we find the whitelist token with the freshest native asset price and exchange rate to the token of interest. We then propagate the price through the pairs exchange rate to find the derived native asset price of the token of interest.
- Derived USD prices are computed after the derived native asset price is computed by using a native asset / USD chainlink price feed.
- Due to the nature of how derived prices are computed, there can be a difference between the lastUpdatedBlock and the lastDerivedPriceBlock. When using derived prices, always consider lastDerivedPriceBlock to know how fresh the price is.
- ERC20 fill roles
- generalized to the following 3 roles and token flow
graph TD source --"input token"--> filler filler --"output token"--> destination
- In native orders:
- maker is the source
- maker token is the input token
- taker is the filler
- taker token is the output token
- it is possible that the input token doesn't actually go to the filler and instead to a recipient the filler specifies (ex batch RFQ orders), we don't explicitly try to derive this as it would require tracking and deriving another role in general (the input token recipient). See the note above about inferring roles where event data doesn't provide this information.
- In native orders:
- generalized to the following 3 roles and token flow
- Erc20Fill.feeRecipient is only used for Limit orders, we cannot accurately track fee recipients for erc20Transforms due to no events being emitted.
- For erc20BridgeFills, the source and destination will always be the flash wallet. This is because the flash wallet is always the address that interacts with the bridge. From the perspective of the individual fill, this is accurate since the input tokens flow from the flash wallet to the filler, and the output tokens flow from filler to flash wallet. This information is what is required to assemble the entire swap for complex swaps (multihop, batch, and/or multiple transforms), see the note above about why we do not attempt to do this assembly at indexing time.
- Historical snapshots are provided on daily and weekly intervals. Ideally these are also provided hourly, but the indexing time increase is too significant.
- Historical snapshots are taken at the start of the interval. All historical data is reported as cumulative, interval volumes can be computed by subtracting the previous intervals value.
- Unique users: the subgraph considers unique users as unique originating addresses of transactions to the 0x protocol. I.e for any fill, there will only be 1 "user", which is the sender of the transaction. The reason we do this is because we don't assemble entire trades, we only consider fills. Many fills source and destination are the zeroEx proxy, or the flash wallet, and the fillers are pools, so considering fill actors (source, filler, destination) would under count unique users in general.
- Aggregated volumes are provided as
volumeUsd
andwhitelistVolumeUsd
:- volumeUsd: input volume of all erc20s, this is likely incorrect since it includes 'shit coins' which might be price manipulated and cause a skew in overall volume. This can be used to reconstruct an accurate total volume by excluding certain tokens which are causing the errors.
- whitelistVolumeUsd: input volume of only whitelisted erc20s, this will be an underestimate on total volume, but more accurate than volumeUsd in general. You can see what tokens are whitelisted by looking at
Erc20Token.whitelisted
, or you can view the list here.
- API key: we provide a free community API key to query the graph's decentralized network deployment, reach out to contract@paperclip.xyz to get it.
- Using the api key: replace [api-key] in the query url (get the query url from the deployment) with the api key
These block diagrams provide an overview of the general functionality of the 0x protocol in the depth required for developing and understanding this subgraph.
graph TD
P[0x Proxy v4] --> E[Erc20Swap]
P --> N[NftSwap]
E --> D[direct]
E --0xProxy::TransformedERC20--> T[TransformErc20]
D --> F[optimized]
F --UniswapV2Pair::Swap--> UniswapV2
F --SushiSwapPair::Swap--> SushiSwap
F --PancakeSwapPair::Swap--> PancakeSwap
F --UniswapV3Pool::Swap--> UniswapV3
D --0xProxy::LiquidityProviderSwap && PlpSandbox::LiquidityProviderFill---> Plp
D --> NA[Native]
NA --0xProxy::LimitOrderFilled--> Limit
NA --0xProxy::RfqOrderFilled--> Rfq
NA --0xProxy::OtcOrderFilled--> Otc
T --> NA
T --FlashWallet::BridgeFill---> Bridge
N --0xProxy::ERC721OrderFilled----> Erc721
N --0xProxy::ERC1155OrderFilled----> Erc1155
erDiagram
ZeroExProxy ||--|| FlashWallet : ""
FlashWallet ||--|{ Bridge : ""
ZeroExProxy ||--|| PlpSandbox : ""
ZeroExProxy ||--|{ Plp : ""
PlpSandbox ||--|{ Plp : ""
ZeroExProxy ||--|{ UniswapV2Pair : ""
ZeroExProxy ||--|{ SushiSwapPair : ""
ZeroExProxy ||--|{ PancakeSwapPair : ""
ZeroExProxy ||--|{ UniswapV3Pool : ""
Top row is all the static data sources with hard coded contract addresses, below that are dynamic data sources
erDiagram
ZeroExProxy
FlashWallet
PlpSandbox
UniswapV2Factory ||--|{ UniswapV2Pair : "PairCreated"
SushiSwapFactory ||--|{ SushiSwapPair : "PairCreated"
PancakeSwapFactory ||--|{ PancakeSwapPair : "PairCreated"
UniswapV3Factory ||--|{ UniswapV3Pool : "PoolCreated"
Multiplex allows composition of all order types:
enum MultiplexSubcall {
Invalid,
RFQ,
OTC,
UniswapV2,
UniswapV3,
LiquidityProvider,
TransformERC20,
BatchSell,
MultiHopSell
}
graph TD
S[Source] --> Subcall1
S --> Subcall2
S --> SubcallN
Subcall1 --> R[Recipient]
Subcall2 --> R
SubcallN --> R
graph TD
S[Source] --> Subcall1
Subcall1 --> Subcall2
Subcall2 --> SubcallN
SubcallN --> R[Recipient]
Note that BatchSell and MultiHopSell can be composed within each other, offering even more flexibility. I.e a subcall of batch could be a multihop and visa versa.
Note: OTC is the only one that supports filling in ETH directly, others can through transforms
graph TD
subgraph C[ERC20 input, ETH output, OTC only]
TC[Taker] --ERC20--> MC[Maker]
MC --WETH--> ZC[ZeroExProxy]
ZC --ETH--> RC[Receipient]
end
subgraph A[ETH input, ERC20 output, OTC only]
T[Taker] --ETH--> Z[ZeroExProxy]
Z --ETH--> M[Maker]
M --ERC20--> R[Receipient]
end
subgraph B[ERC20 input + output]
TB[Taker] --ERC20--> MB[Maker]
MB--ERC20--> RB[Receipient]
end
graph TD
subgraph ETH output
SB[sender] --"(1) ERC20"--> PB[Pools]
PB --"(2) ERC20"--> PB
PB --"(3) WETH"--> ZB[ZeroExProxy]
ZB[ZeroExProxy] <--"(4) WETH/ETH"--> WB[WETH]
ZB --"(5) ETH"--> RB[Recipient]
end
subgraph ETH input
SA[sender] --"(1) ETH"--> ZA[ZeroExProxy]
ZA <--"(2) ETH / WETH"--> WA[WETH]
ZA --"(3) WETH"--> PA[Pools]
PA --"(4) ERC20"--> PA
PA --"(5) ERC20"--> RA[Recipient]
end
subgraph ERC20 input and output
SC[sender] --"(1) ERC20"--> PC[Pools]
PC --"(2) ERC20"--> PC
PC --"(3) ETH"--> RC[Recipient]
end
graph TD
U[Sender] --"(1, using proxy as payer) ETH or ERC20"--> P[ZeroExProxy]
P --"(1, using proxy as payer) ETH or ERC20"--> F[FlashWallet]
U --"(1, using sender as payer) ERC20"--> F
F <--"(2: FillQuoteTransformer->fillBridge) ETH or ERC20"--> B[Bridge]
F <--"(2: FillQuoteTransformer->NativeOrder) ETH or ERC20"--> NativeOrderMaker
F <--"(2: WethTransformer) WETH / ETH"--> W[WETH]
F --"(3: AffiliateFeeTransformer) ETH or ERC20"----> FeeRecipient
F --"(3: PayTakerTransformer) ETH or ERC20"----> Recipient
graph TD
subgraph B[ETH output]
SB[Sender] --ERC20--> BB[Provider]
BB --ETH--> RB[Receipient]
end
subgraph A[ETH input]
SA[Sender] --ETH--> ZA[ZeroExProxy]
ZA --ETH--> PA[Provider]
PA --ERC20--> RA[Receipient]
end
subgraph C[ERC20 input and output]
SC[Sender] --ERC20--> BC[Provider]
BC --ERC20--> RC[Receipient]
end
Any
<network>
below is to be replaced with one of the supported networks: [mainnet, optimism, arbitrum, base, polygon, bnb, avalanche, fantom, celo]
Install dependencies
yarn install
Copy .env.example to .env and populate it
cp .env.example .env
Run code generation
yarn codegen
Build
yarn build:<network>
Deploy to the hosted network
yarn deploy-hosted:<network>
Deploy to the subgraph studio (version controlled with STUDIO_VERSION in .env)
yarn deploy-studio:<network>
Codegen, build and deploy everywhere in one command
yarn auto-deploy:<network>
Autodeploy to hosted and studio for all networks
yarn auto-deploy:all
Local mainnet development
# Create subgraph (only need first time)
yarn create-local
# Deploy
yarn deploy-local
# Remove
yarn remove-local
This can be added to the end of subgraph.yaml
to graft to an existing subgraph for debugging and fixing indexing errors.
features:
- grafting # feature name
graft:
base: Qm... # subgraph ID of base subgraph
block: 1502122 # block number
- 0x addresses: https://github.com/0xProject/protocol/blob/development/packages/contract-addresses/addresses.json
- UniswapV2: https://docs.uniswap.org/contracts/v2/reference/smart-contracts/factory
- SushiSwap: https://docs.sushi.com/docs/Products/Classic%20AMM/Deployment%20Addresses
- PancakeSwap: https://docs.pancakeswap.finance/developers/smart-contracts/pancakeswap-exchange/v2-contracts/factory-v2
- UniswapV3: https://docs.uniswap.org/contracts/v3/reference/deployments
- Chainlink price feeds: https://docs.chain.link/data-feeds/price-feeds/addresses?network=base&page=1&search=ETH+%2F+USD
- Validation Spreadsheet: summarizes all validation
- Notebooks: these are used to extract data for the validation spreadsheet
- historical: extracts and plots subgraph historical data
- current: extracts subgraph current data (tip)
- external: extracts data from external API's