Kodiak Finance
  • OVERVIEW
    • 🐻‍❄️Introducing Kodiak
    • 🐻Kodiak x Berachain
    • ✉️Contact Us
    • 🍯Kodiak Contracts
  • 🅱️Kodiak-Boyco
  • PROTOCOL
    • 🔃DEX
      • Swaps
      • Liquidity Provision
      • Trading Fees
    • 🏝️Islands
      • Island Liquidity Provision
      • Sweetened Islands
      • Auto-BGT
    • 🐼Panda Factory
  • 🪙Tokenomics
    • Kodiak Pre-TGE Rewards
  • 🧠User Guide
    • Launch a Token Launch on Panda Factory
    • Trading on Panda Factory
    • Swap
    • Create a V2 Position
    • Create a V3 Position
    • Add/Stake Islands Liquidity
    • Migrating to a Reward Vault
    • Deploying new Permissonless Islands
    • Deploying and Configuring a Kodiak Farm
    • Add your token
  • Add Your Project to the Ecosystem
  • 👨‍💻Developers
    • 🐼Panda
      • Technical Integration Guide
      • Subgraph
        • Entity Reference
        • Query Guide
        • Advanced Usage Guide
      • Smart Contract Reference
        • Panda Factory
        • Panda Pool
        • Panda Token
      • Api
    • Farms
      • Technical Integration Guide
      • Smart Contract Reference
    • 🌴Kodiak Islands
      • Technical Integration Guide
        • Understanding Token Deposit Ratio
      • Subgraph
        • Entity Reference
        • Query Guide
        • Advanced Usage Guide
      • Smart Contract Reference
        • Kodiak Island Factory
        • Kodiak Island
        • Kodiak Island Router
      • Api
    • 💰Pricing with Subgraph
    • 💱Quotes
    • Backend
  • 🛡️SECURITY
    • 🔍Audits
  • ℹ️Informational
    • 📜Terms of Use
    • 🔏Privacy Policy
    • TradingView Advanced License
Powered by GitBook
On this page
  1. Developers
  2. Kodiak Islands
  3. Subgraph

Advanced Usage Guide

This guide covers advanced topics and strategies for working with the Kodiak Islands subgraph, including complex querying patterns, integration strategies, performance optimization, and custom analytics.

Complex Querying Patterns

Fragment Reuse

For complex applications that frequently query similar fields, use GraphQL fragments to reduce duplication:

fragment VaultBasicInfo on KodiakVault {
  id
  name
  symbol
  totalValueLockedUSD
  apr {
    averageApr
  }
}

fragment VaultDetailedInfo on KodiakVault {
  ...VaultBasicInfo
  inputToken {
    symbol
    decimals
  }
  outputToken {
    symbol
    decimals
  }
  pricePerShare
  _token0Amount
  _token1Amount
  _token0AmountUSD
  _token1AmountUSD
}

query {
  topVaults: kodiakVaults(
    first: 5
    orderBy: totalValueLockedUSD
    orderDirection: desc
  ) {
    ...VaultBasicInfo
  }
  
  specificVault: kodiakVault(id: "0x1234567890abcdef") {
    ...VaultDetailedInfo
  }
}

Dynamic Querying with Variables

Use GraphQL variables for dynamic queries:

query GetVaultPerformance($vaultId: ID!, $startTime: BigInt!, $endTime: BigInt!) {
  snapshots: kodiakVaultDailySnapshots(
    where: {
      vault: $vaultId
      timestamp_gte: $startTime
      timestamp_lte: $endTime
    }
    orderBy: timestamp
  ) {
    timestamp
    totalValueLockedUSD
    dailyTotalFeesUSD
    apr
  }
}

This query can be executed with variables:

{
  "vaultId": "0x1234567890abcdef",
  "startTime": "1640995200",
  "endTime": "1672531200"
}

Advanced Filtering Combinations

Combine multiple filters for complex data selection:

query HighPerformingVaults {
  kodiakVaultDailySnapshots(
    where: {
      apr_gt: "20"                      # APR > 20%
      totalValueLockedUSD_gt: "500000"  # TVL > $500,000
      dailyTotalFeesUSD_gt: "1000"      # Daily fees > $1,000
      timestamp_gt: "1648771200"        # After April 1, 2022
    }
    orderBy: apr
    orderDirection: desc
  ) {
    vault {
      id
      name
    }
    timestamp
    apr
    totalValueLockedUSD
    dailyTotalFeesUSD
  }
}

Time Series Analysis

Calculating Period-over-Period Changes

To calculate weekly changes in vault performance:

query WeeklyPerformanceChange($vaultId: ID!) {
  thisWeek: kodiakVaultDailySnapshots(
    first: 7
    orderBy: timestamp
    orderDirection: desc
    where: { vault: $vaultId }
  ) {
    timestamp
    totalValueLockedUSD
    dailyTotalFeesUSD
    volumeUSD
    apr
  }
  
  previousWeek: kodiakVaultDailySnapshots(
    first: 7
    skip: 7
    orderBy: timestamp
    orderDirection: desc
    where: { vault: $vaultId }
  ) {
    timestamp
    totalValueLockedUSD
    dailyTotalFeesUSD
    volumeUSD
    apr
  }
}

With this data, you can calculate week-over-week changes for key metrics in your application:

function calculateChangePercentage(current: number, previous: number): number {
  if (previous === 0) return 0;
  return ((current - previous) / previous) * 100;
}

// Calculate aggregate values for each week
const thisWeekTVL = average(thisWeekData.map(d => parseFloat(d.totalValueLockedUSD)));
const prevWeekTVL = average(previousWeekData.map(d => parseFloat(d.totalValueLockedUSD)));

const thisWeekFees = sum(thisWeekData.map(d => parseFloat(d.dailyTotalFeesUSD)));
const prevWeekFees = sum(previousWeekData.map(d => parseFloat(d.dailyTotalFeesUSD)));

// Calculate percentage changes
const tvlChange = calculateChangePercentage(thisWeekTVL, prevWeekTVL);
const feesChange = calculateChangePercentage(thisWeekFees, prevWeekFees);

Analyzing APR Trends

Track APR trends over longer periods to identify patterns:

query AprTrends($vaultId: ID!) {
  daily: kodiakVaultDailySnapshots(
    first: 90  # Last 90 days
    orderBy: timestamp
    orderDirection: desc
    where: { vault: $vaultId }
  ) {
    timestamp
    apr
    totalValueLockedUSD
  }
}

You can use this data to:

  • Calculate moving averages (7-day, 30-day)

  • Identify seasonal patterns

  • Correlate APR changes with TVL or other metrics

  • Build predictive models for APR forecasting

Integration Strategies

Real-time Data Updates

For applications requiring real-time data, implement a polling strategy:

// Fetch latest vault data every 60 seconds
function setupPolling(vaultId: string) {
  const query = `
    query GetVaultData($id: ID!) {
      kodiakVault(id: $id) {
        totalValueLockedUSD
        pricePerShare
        apr {
          averageApr
        }
      }
    }
  `;
  
  setInterval(() => {
    executeQuery(query, { id: vaultId })
      .then(data => updateUI(data.kodiakVault))
      .catch(error => handleError(error));
  }, 60000);
}

Combining with On-chain Data

For some advanced use cases, you may need to combine subgraph data with direct on-chain calls:

async function getCompleteVaultData(vaultId: string) {
  // Get historical and aggregated data from subgraph
  const subgraphData = await fetchFromSubgraph(vaultId);
  
  // Get real-time position data from the blockchain
  const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
  const vaultContract = new ethers.Contract(vaultId, VAULT_ABI, provider);
  const currentPosition = await vaultContract.getCurrentPosition();
  
  // Combine the data
  return {
    ...subgraphData,
    currentPosition: {
      lowerTick: currentPosition.lowerTick.toString(),
      upperTick: currentPosition.upperTick.toString(),
      liquidity: currentPosition.liquidity.toString()
    }
  };
}

Building Custom Analytics

Create custom analytics by combining multiple queries:

async function vaultPerformanceAnalytics(vaultId: string) {
  // Fetch basic vault info
  const vaultInfo = await fetchVaultInfo(vaultId);
  
  // Fetch historical data
  const dailyData = await fetchDailySnapshots(vaultId, 90); // Last 90 days
  
  // Fetch user activity
  const deposits = await fetchDeposits(vaultId);
  const withdrawals = await fetchWithdrawals(vaultId);
  
  // Calculate custom metrics
  const userRetentionRate = calculateUserRetention(deposits, withdrawals);
  const volatilityScore = calculateVolatility(dailyData.map(d => d.apr));
  const performanceScore = calculatePerformanceScore(
    vaultInfo.apr.averageApr,
    volatilityScore,
    userRetentionRate
  );
  
  return {
    vaultInfo,
    userRetentionRate,
    volatilityScore,
    performanceScore,
    dailyTrends: processDailyTrends(dailyData)
  };
}

Performance Optimization

Query Optimization

Optimize your queries to reduce response time and load on the subgraph:

  1. Select only necessary fields:

    # Instead of this
    {
      kodiakVaults {
        id
        name
        symbol
        # ... many more fields
      }
    }
    
    # Do this
    {
      kodiakVaults {
        id
        name
        totalValueLockedUSD
        # Only the fields you need
      }
    }
  2. Limit result sizes:

    {
      kodiakVaults(first: 20) {
        # fields
      }
    }
  3. Use efficient filtering:

    # Instead of fetching all and filtering client-side
    {
      kodiakVaults(where: { totalValueLockedUSD_gt: "1000000" }) {
        # fields
      }
    }

Client-Side Caching

Implement caching to reduce redundant queries:

// Simple in-memory cache example
const cache = new Map();

async function fetchWithCache(query, variables, maxAge = 60000) {
  const cacheKey = JSON.stringify({ query, variables });
  
  if (cache.has(cacheKey)) {
    const { data, timestamp } = cache.get(cacheKey);
    if (Date.now() - timestamp < maxAge) {
      return data;
    }
  }
  
  const result = await executeQuery(query, variables);
  cache.set(cacheKey, {
    data: result,
    timestamp: Date.now()
  });
  
  return result;
}

Batching Queries

For applications that need multiple related pieces of data, batch your queries:

query BatchedData($vaultId: ID!) {
  vault: kodiakVault(id: $vaultId) {
    id
    name
    totalValueLockedUSD
    apr {
      averageApr
    }
  }
  
  recentDeposits: kodiakDeposits(
    first: 5,
    orderBy: timestamp,
    orderDirection: desc,
    where: { vault: $vaultId }
  ) {
    timestamp
    amountUSD
  }
  
  dailyStats: kodiakVaultDailySnapshots(
    first: 7,
    orderBy: timestamp,
    orderDirection: desc,
    where: { vault: $vaultId }
  ) {
    timestamp
    dailyTotalFeesUSD
  }
}

Advanced Use Cases

Strategy Analysis

Analyze the effectiveness of different vault strategies by tracking changes to tick ranges:

query StrategyEffectiveness($vaultId: ID!) {
  # Get all snapshots and process client-side
  snapshots: kodiakVaultDailySnapshots(
    orderBy: timestamp
    where: { vault: $vaultId }
  ) {
    timestamp
    lowerTick
    upperTick
    # If tickChanges is available in your snapshots, include it
    tickChanges {
      timestamp
      lowerTick
      upperTick
    }
    dailyTotalFeesUSD
    apr
  }
}

This data can be used to:

  • Compare APR before and after strategy changes

  • Identify optimal tick ranges for different market conditions

  • Evaluate the effectiveness of strategy adjustments

Portfolio Analysis

For users with positions across multiple vaults, build portfolio analytics:

query UserPortfolio($userAddress: String!) {
  # Get all user deposits
  deposits: kodiakDeposits(
    where: { from: $userAddress }
    orderBy: timestamp
  ) {
    vault {
      id
      name
      _token0 { 
        symbol 
      }
      _token1 { 
        symbol 
      }
    }
    timestamp
    amount
    amountUSD
  }
  
  # Get all user withdrawals
  withdrawals: kodiakWithdraws(
    where: { to: $userAddress }
    orderBy: timestamp
  ) {
    vault {
      id
      name
    }
    timestamp
    amount
    amountUSD
  }
}

With this data, you can:

  • Calculate user's net position in each vault

  • Estimate their portfolio value over time

  • Calculate portfolio-wide performance metrics

Vault Comparison Tool

Build a tool to compare performance across vaults:

query CompareVaults($vaultIds: [ID!]!) {
  vaults: kodiakVaults(
    where: { id_in: $vaultIds }
  ) {
    id
    name
    _token0 { 
      symbol 
    }
    _token1 { 
      symbol 
    }
    totalValueLockedUSD
    apr { 
      averageApr 
    }
    weeklyFeesEarnedUSD
  }
  
  # Get daily performance for each vault (last 30 days)
  dailyPerformance: kodiakVaultDailySnapshots(
    first: 30
    orderBy: timestamp
    orderDirection: desc
    where: { vault_in: $vaultIds }
  ) {
    vault { 
      id 
    }
    timestamp
    apr
    dailyTotalFeesUSD
    totalValueLockedUSD
  }
}

Working with Time Series Data

When working with time series data from the Kodiak Islands subgraph, consider these strategies:

  1. Handling Missing Data Points: Daily and hourly snapshots may have missing data points. Implement interpolation strategies in your application to handle these gaps.

  2. Normalizing Timestamps: Convert Unix timestamps to your local timezone for display:

    function formatTimestamp(unixTimestamp) {
      return new Date(unixTimestamp * 1000).toLocaleString();
    }
  3. Grouping Data: For longer time ranges, group data into periods (weekly, monthly):

    function groupDataByWeek(dailyData) {
      const weeklyData = {};
      dailyData.forEach(day => {
        const weekNumber = getWeekNumber(day.timestamp);
        if (!weeklyData[weekNumber]) {
          weeklyData[weekNumber] = {
            totalFeesUSD: 0,
            avgTVL: 0,
            daysCount: 0
          };
        }
        weeklyData[weekNumber].totalFeesUSD += parseFloat(day.dailyTotalFeesUSD);
        weeklyData[weekNumber].avgTVL += parseFloat(day.totalValueLockedUSD);
        weeklyData[weekNumber].daysCount += 1;
      });
      
      // Calculate averages
      Object.keys(weeklyData).forEach(week => {
        weeklyData[week].avgTVL /= weeklyData[week].daysCount;
      });
      
      return weeklyData;
    }

Conclusion

This advanced guide has covered complex querying patterns, integration strategies, performance optimization, and various use cases for the Kodiak Islands subgraph. By leveraging these techniques, you can build sophisticated applications that provide powerful insights into the Kodiak Islands protocol and its vaults.

Remember that subgraph queries can be resource-intensive, so always optimize your queries and implement appropriate caching strategies. For very large-scale applications, consider implementing additional middleware to handle complex data processing and caching.

For any questions or issues with the subgraph, refer to the official Kodiak Islands documentation or contact the protocol team for support.

PreviousQuery GuideNextSmart Contract Reference

Last updated 1 month ago

👨‍💻
🌴