Skip to main content

DEXTrades Cube

The DEXTrades cube provides comprehensive information about the dex trading data, such as buyer, seller, token prices, pairs, transactions, etc.

Advanced Usage Note: This documentation includes advanced patterns for processing DEXTrades data based on production implementations. These patterns help handle complex scenarios like multi-hop swaps, proxy contracts, and proper volume calculations.

Import Note: If there is a trade between 2 addresses, the details in Buy{} dropdown are pool details, and the information displayed in the DEXTrades cube is from the pool's perspective.

Let's understand the concept of buyer and seller. Token X and token Y swap as above.

If we see the trade from user A's side, then we get the following:

  • User A becomes the seller of token X.
  • User A becomes the buyer of token Y.

Now, if we see the trade from a user B side, we get the following.

  • User B becomes the seller of token Y.
  • User B becomes the buyer of token X.

Therefore, buyers and sellers change relatively when the trade sides change.

It is important to note that a pool is always involved; whenever any trade occurs between two traders, one must be a pool. Thus, we are considering User B as a pool.

Understanding DEXTrade Cube data​

Next, we understand how the Dextrades Cube displays the result:

Take this query for example:

{
EVM(network: eth, dataset: archive) {
DEXTrades(
orderBy: {descending: Block_Time}
limit: {count: 50}
where: {TransactionStatus: {Success: true}, Block: {Number: {eq: "23674719"}}, Transaction: {Hash: {is: "0x0891b30722d44284d0c110c761190ecd6ad0f33946835bbde164561d847f5c87"}}}
) {
Trade {
Buy {
Buyer
Amount
Price
Currency {
SmartContract
Name
}
}
Dex {
Pair {
Name
SmartContract
}
ProtocolName
}
Sell {
Buyer
Amount
Currency {
Name
SmartContract
}
}
}
Transaction {
Hash
}
}
}
}


Output

{
"EVM": {
"DEXTrades": [
{
"Trade": {
"Buy": {
"Amount": "4002.603343842926485635",
"Buyer": "0xad4e4954b2f22525f5c9d7e7182fff9cf251d0f7",
"Currency": {
"Name": "MUSKITO Token",
"SmartContract": "0x7ef790d9bccc87989be0fdb88ffb955bec3d5e92"
},
"Price": 6.700259580759855e-9
},
"Dex": {
"Pair": {
"Name": "Uniswap V2",
"SmartContract": "0xad4e4954b2f22525f5c9d7e7182fff9cf251d0f7"
},
"ProtocolName": "uniswap_v2"
},
"Sell": {
"Amount": "0.000026818481402565",
"Buyer": "0x5fbf1aba26bf1493cd7677ad4ec25d96a91ab0ec",
"Currency": {
"Name": "Wrapped Ether",
"SmartContract": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
}
}
},
"Transaction": {
"Hash": "0x0891b30722d44284d0c110c761190ecd6ad0f33946835bbde164561d847f5c87"
}
}
]
}
}

Analyzing the DEXTrades Output​

Let's break down how DEXTrades presents data from the pool's perspective:

Key Observations:

  1. Pool Identification: The Buy.Buyer address matches the Dex.Pair.SmartContract address.

  2. Buy Side (Pool's Perspective):

    • Currency: The token that the pool received (project token)
    • Amount: Quantity of tokens the pool received
    • Buyer: Pool address (the pool is "buying" these tokens)
    • Price: Current trading price per token
  3. Sell Side (Pool's Perspective):

    • Currency: The payment token (WETH, stablecoins, etc.)
    • Amount: Quantity of payment tokens the pool gave out
    • Buyer: User address who received the payment tokens

What Actually Happens:

From the pool's perspective (which is what DEXTrades shows):

  • The pool bought project tokens (received them from user)
  • The pool sold payment tokens (gave them to user)

From the user's perspective (the actual trader):

  • User sold project tokens to the pool
  • User bought payment tokens (WETH/stablecoins) in return

Metrics in DEXTrades Cube​

Metrics allow for sum, count, average, median, maximum, minimum, and more calculations

The count metric can easily retrieve a specific token's total number of trades. Run this API to find the total trades of PEPE "0x698…" tokens in the Uniswap v3 factory "0x1f984…" in the ethereum network.

query MyQuery {
EVM(dataset: archive, network: eth) {
DEXTradeByTokens(
where: {TransactionStatus: {Success: true},
Trade: {Currency:
{SmartContract:
{is: "0x6982508145454ce325ddbe47a25d4ec3d2311933"}},
Dex:
{OwnerAddress:
{is: "0x1f98431c8ad98523631ae4a59f267346ea31f984"}}},
Block: {Date:
{since: "2024-01-01", till: "2024-06-02"}}}
) {
total_trades: count
}
}
}

How Does Bitquery Calculate USD Price for a Token?​

Bitquery calculates the token price using a simple formula:

UsdPrice of token 1 = amount2 in USD / amount1 UsdPrice of token 2 = amount1 in USD / amount2

If either of these amounts is missing, the price cannot be determined. To better understand token prices, one must first examine the trade amounts involved.

It's important to note that this "price" is not the actual market price of the token, but rather a derivative based on the trade amounts.

Example: BAR/WETH Pair
BAR Price in USD = WETH amount in USD / Amount of BAR tokens
WETH Price in USD = BAR amount in USD / Amount of WETH tokens

In this example, the second calculation (WETH Price) may not be accurate because the BAR amount in USD is unknown.

Example: WETH/USDT Pair
USDT Price in USD = WETH amount in USD / Amount of USDT tokens
WETH Price in USD = USDT amount in USD / Amount of WETH tokens

In this case, both values make sense, as both WETH and USDT can be valued in USD directly.

Multi-Hop Trade Detection and Processing​

When processing DEXTrades data in production applications, it's crucial to handle multi-hop swaps correctly. Multi-hop trades occur when a single transaction contains multiple DEX trades that are part of one logical swap operation (e.g., Token A → WETH → Token B).

Identifying Multi-Hop Trades​

Multi-hop trades can be detected by:

  1. Same Transaction Hash: All trades in a multi-hop swap share the same transaction hash
  2. Sequential Processing: Trades appear in sequence within the same block following the Trade_Index
  3. Token Chain Logic: The sell token of one trade matches the buy token of the next

Processing Strategy​

For multi-hop trades, use this approach:

  • Token Identification: Use the first hop to identify the actual token being swapped (not the intermediate tokens)
  • Volume Calculation: Use the last hop to determine the final payment amount
  • Direction Detection: Check the signer's role in the final hop to determine if it's a buy or sell
# Example pattern for multi-hop detection
if tx_hash in processed_transactions:
# This is part of a multi-hop swap
first_hop = processed_transactions[tx_hash][0]
current_hop = trade_data # Last hop seen

# Get actual token from first hop (exclude payment tokens)
actual_token = get_non_payment_token(first_hop)

# Get final volume from last hop payment side
final_volume = get_payment_side_amount(current_hop)

# Determine buy/sell from signer's role in last hop
is_buy = signer_is_buyer_in_final_hop(current_hop, signer)

Payment Token Classification​

Different token types require different processing logic:

  • Native Tokens: 0x (ETH), direct BNB trades
  • Wrapped Tokens: WETH, WBNB - used for volume calculations
  • Stablecoins: USDT, USDC, DAI - also payment tokens
  • Other Tokens: Project tokens, memecoins, etc.

Advanced Buyer/Seller Logic and Proxy Contracts​

Understanding BitQuery's Buy/Sell Fields​

In EVM chains, DEXTrades data, as we see above, the Buy fields represent the pool's events.

Handling Different Scenarios​

When processing trades, check multiple scenarios for accurate buyer/seller identification:

Scenario 1: Direct Signer Matches​

# Check if signer is directly in buy/sell fields
if signer == buy_buyer:
# Signer bought the token
process_as_buy()
elif signer == sell_seller:
# Signer sold the token
process_as_sell()

Scenario 2: Proxy Contract Logic​

When the signer doesn't appear in buyer/seller fields (common with proxy contracts):

# Find consistent party across both sides
if buy_buyer == sell_seller:
# This party appears to buy token and sell payment
# BUT for proxy contracts, logic is inverted
if signer != buy_buyer:
# Signer used proxy -> opposite action
process_as_sell() # Inverted logic
elif buy_seller == sell_buyer:
# This party appears to sell token and buy payment
# BUT for proxy contracts, logic is inverted
if signer != buy_seller:
# Signer used proxy -> opposite action
process_as_buy() # Inverted logic

Trade Type Classification​

Different trade types require specific handling:

1. Native Token Trades​

# Direct BNB/ETH trades (sell_contract = "0x")
where: {
Trade: {
Sell: { Currency: { SmartContract: { is: "0x" } } }
}
}

2. Wrapped Token Trades​

# WETH/WBNB trades
where: {
Trade: {
Buy: { Currency: { SmartContract: { is: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } } }
}
}

3. Token-to-Token Swaps​

# Both sides are tokens (not native/wrapped)
where: {
Trade: {
Buy: { Currency: { SmartContract: { not: "0x" } } },
Sell: { Currency: { SmartContract: { not: "0x" } } }
}
}

Common Edge Cases and Filtering Strategies​

Filtering MEV Bots and Unwanted Trades​

Production applications often need to filter out certain types of trades:

# Filter out specific MEV bot contracts
query FilterMEVBots {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {
Transaction: {
To: { notIn: ["0x802b65b5d9016621e66003aed0b16615093f328b"] }
}
}
) {
# Your trade data
}
}
}

Handling Zero Value Trades​

Filter out trades with zero amounts or prices:

query FilterZeroTrades {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {
Trade: {
Buy: {
Amount: { gt: "0" },
PriceInUSD: { gt: 0 }
},
Sell: {
Amount: { gt: "0" },
PriceInUSD: { gt: 0 }
}
}
}
) {
# Your trade data
}
}
}

Identifying Pool vs Trader Addresses​

For token-to-token swaps, distinguish between pool addresses and actual traders:

# Focus on specific signer addresses (real traders)
query RealTraders {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {
Transaction: {
Signer: { is: "0x742d35Cc6334C0532925a3b8C836f4b98C6b1e96" }
}
}
) {
Transaction {
Signer
}
Trade {
Buy {
Buyer
Seller
}
Sell {
Buyer
Seller
}
}
}
}
}

Transaction Status Filtering​

Always filter for successful transactions:

query SuccessfulTrades {
EVM(dataset: combined, network: eth) {
DEXTrades(
where: {
TransactionStatus: { Success: true }
}
) {
# Your trade data
}
}
}

Video Tutorial | Why PriceInUSD is 0 in Bitquery API response?​