> ## Documentation Index
> Fetch the complete documentation index at: https://kamino.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Calculate Reserve Reward APY

> Calculate collateral and debt farm reward APY for market reserves

<Note>
  **Reserve Farms vs Extra Farms**

  Reserve farms are attached directly to a reserve and reward all users who deposit or borrow that reserve asset. Depositors earn rewards through collateral farms, while borrowers earn rewards through debt farms.

  Extra farms reward users only when specific collateral and debt combinations are used. Rewards are conditional on holding qualifying positions rather than simply depositing or borrowing a single reserve.

  This tutorial focuses on reserve farms.
</Note>

## Calculate Reserve Reward APY

Calculate APY for both collateral and debt farm rewards on a specific reserve.

<Steps>
  <Step>
    ### Import Dependencies

    Import the required packages for Solana RPC communication, Kamino SDK operations, and decimal calculations.

    ```typescript theme={null}
    import { createSolanaRpc, address, type Address } from '@solana/kit';
    import { KaminoMarket, PROGRAM_ID, lamportsToNumberDecimal } from '@kamino-finance/klend-sdk';
    import { FarmState, calculateCurrentRewardPerToken } from '@kamino-finance/farms-sdk';
    import Decimal from 'decimal.js';

    type PriceData = { mint: string; price: string };

    const DEFAULT_PUBKEY = '11111111111111111111111111111111';
    ```
  </Step>

  <Step>
    ### Initialize RPC and Fetch Prices

    Set up the Solana RPC connection and fetch token prices from the Kamino API.

    ```typescript theme={null}
    const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
    const mainMarket = address('7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF');
    const usdsMint = address('USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA');

    // Fetch token prices from Kamino API
    const pricesRes = await fetch('https://api.kamino.finance/oracles/prices?markets=main');
    const pricesData = (await pricesRes.json()) as PriceData[];
    const priceMap = new Map<string, number>();
    for (const p of pricesData) {
      priceMap.set(p.mint, parseFloat(p.price));
    }
    ```

    <Info>
      Creating a price map allows quick lookups for multiple reward tokens. The example uses USDS reserve which has both collateral and debt farm rewards active.
    </Info>
  </Step>

  <Step>
    ### Load Market and Reserve

    Load the Kamino market and get the reserve by its mint address.

    ```typescript theme={null}
    // Load market and reserve
    const market = await KaminoMarket.load(rpc, mainMarket, 400, PROGRAM_ID);
    const reserve = market!.getReserveByMint(usdsMint);

    if (!reserve) {
      console.log('Reserve not found');
    } else {
    ```

    <Info>
      The `getReserveByMint` method retrieves the reserve configuration including references to both the collateral farm and debt farm addresses.
    </Info>
  </Step>

  <Step>
    ### Collect and Fetch Farm Addresses

    Collect both collateral and debt farm addresses, checking they're not the default pubkey, then fetch all farms in parallel.

    ```typescript theme={null}
      // Collect debt and collateral farm addresses
      const farmsToFetch: { name: string; address: Address }[] = [];
      if (reserve.state.farmCollateral.toString() !== DEFAULT_PUBKEY) {
        farmsToFetch.push({ name: 'Collateral Farm Rewards', address: reserve.state.farmCollateral });
      }
      if (reserve.state.farmDebt.toString() !== DEFAULT_PUBKEY) {
        farmsToFetch.push({ name: 'Debt Farm Rewards', address: reserve.state.farmDebt });
      }

      // Fetch all farms in batch
      const farmAddresses = farmsToFetch.map((f) => f.address);
      const farmStates = await FarmState.fetchMultiple(rpc, farmAddresses);

      const farms = farmsToFetch.flatMap((farmInfo, index) => {
        const state = farmStates[index];
        return state ? [{ name: farmInfo.name, state }] : [];
      });
    ```

    <Info>
      Checking for the default pubkey ensures we only fetch farms that are actually configured on the reserve. Using `FarmState.fetchMultiple` fetches all farm states in a single batch request, which is more efficient than individual fetches.
    </Info>
  </Step>

  <Step>
    ### Calculate Farm Reward APY

    Calculate APY for each active reward on both collateral and debt farms.

    ```typescript theme={null}
      for (const farm of farms) {
        const totalStaked = lamportsToNumberDecimal(
          farm.state.totalStakedAmount.toString(),
          farm.state.token.decimals.toNumber() || 6
        );

        console.log(farm.name + ':');
        for (const rewardInfo of farm.state.rewardInfos) {
          if (rewardInfo.rewardsAvailable.gtn(0) && !totalStaked.isZero()) {
            const rewardMint = rewardInfo.token.mint.toString();
            const rewardPrice = priceMap.get(rewardMint) || 1;
            const currentTime = new Decimal(Date.now() / 1000);

            // Calculate APY from farm rewards
            const rewardPerTokenPerSecond = calculateCurrentRewardPerToken(rewardInfo, currentTime); // returns the raw value
            const divisor = new Decimal(10)
              .pow(rewardInfo.rewardsPerSecondDecimals.toString())
              .mul(new Decimal(10).pow(rewardInfo.token.decimals.toString()));
            const adjustedRewardPerToken = new Decimal(rewardPerTokenPerSecond).div(divisor);
            const dailyRewards = adjustedRewardPerToken.mul(86400).mul(rewardPrice);
            const apy = Decimal.pow(dailyRewards.div(totalStaked).plus(1), 365).minus(1);

            console.log(`  Reward Token: ${rewardMint}`);
            console.log(`  APY: ${(apy.toNumber() * 100).toFixed(2)}%\n`);
          }
        }
      }
    }
    ```

    <Check>
      The script outputs APY for all active rewards on both the collateral and debt farms. The `calculateCurrentRewardPerToken` helper from farms-sdk handles the reward schedule logic. Each reward is priced in USD and the total staked amount represents the value of all positions earning that reward.
    </Check>
  </Step>
</Steps>
