Разработка системы учета стейкинг-наград для налогов

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы учета стейкинг-наград для налогов
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка системы учета стейкинг-наград для налогов

Staking rewards — один из наиболее спорных вопросов крипто-налогообложения. В США IRS (Rev. Rul. 2023-14) официально подтвердил: staking rewards — ordinary income в момент получения по fair market value. В Германии — другая трактовка. Система должна учитывать юрисдикционные различия.

Типы стейкинга и их налоговая трактовка

const STAKING_TAX_TREATMENT: Record<string, StakingTaxRule> = {
  NATIVE_STAKING: {
    // ETH 2.0, SOL, ADA — прямой staking в network
    US: { type: "ordinary_income", timing: "on_receipt" },
    DE: { type: "other_income", timing: "on_receipt", annualExempt: 256 },
    UK: { type: "miscellaneous_income", timing: "on_receipt" },
  },
  LIQUID_STAKING: {
    // stETH, rETH, mSOL — получаешь liquid токен
    // Спорно: является ли получение stETH taxable?
    US: { type: "unknown", note: "IRS не высказался явно" },
    DE: { type: "non_taxable", note: "swap рассматривается как продолжение" },
  },
  REBASING: {
    // stETH rebasing — баланс увеличивается, не отдельные reward транзакции
    US: { type: "ordinary_income", timing: "on_receipt", challenge: "hard_to_track" },
  },
  VALIDATOR_REWARDS: {
    // Операторы ETH validator — в некоторых трактовках business income
    US: { type: "business_income_or_ordinary_income" },
  },
};

Tracking staking rewards

class StakingRewardTracker {
  // Ethereum staking via Lido
  async trackLidoRewards(walletAddress: string, since: Date): Promise<StakingReward[]> {
    // stETH использует rebasing — баланс обновляется ежедневно
    // Нужно snapshots на каждый rebase
    
    const rebaseEvents = await this.getLidoRebaseEvents(since);
    const rewards: StakingReward[] = [];
    
    let previousBalance = await this.getStETHBalance(walletAddress, since);
    
    for (const rebase of rebaseEvents) {
      const newBalance = await this.getStETHBalance(walletAddress, rebase.timestamp);
      const rewardAmount = newBalance - previousBalance;
      
      if (rewardAmount > 0) {
        const ethPrice = await this.priceService.getHistoricalPrice("stETH", rebase.timestamp);
        
        rewards.push({
          timestamp: rebase.timestamp,
          protocol: "Lido",
          asset: "stETH",
          amount: rewardAmount,
          usdValue: rewardAmount * ethPrice,
          rewardType: "REBASING",
          costBasis: rewardAmount * ethPrice, // cost basis = FMV при получении
        });
      }
      
      previousBalance = newBalance;
    }
    
    return rewards;
  }
  
  // Ethereum 2.0 validator rewards
  async trackETH2ValidatorRewards(validatorIndex: number, since: Date): Promise<StakingReward[]> {
    const beaconChainData = await fetch(
      `https://beaconcha.in/api/v1/validator/${validatorIndex}/incomedetail?limit=100`
    ).then(r => r.json());
    
    return beaconChainData.data
      .filter((r: any) => new Date(r.epoch_timestamp) >= since)
      .map(async (r: any) => {
        const timestamp = new Date(r.epoch_timestamp);
        const ethPrice = await this.priceService.getHistoricalPrice("ETH", timestamp);
        const rewardETH = r.income.attestation_source_reward / 1e9; // gwei → ETH
        
        return {
          timestamp,
          protocol: "Ethereum 2.0 Validator",
          asset: "ETH",
          amount: rewardETH,
          usdValue: rewardETH * ethPrice,
          validatorIndex,
          epoch: r.epoch,
        };
      });
  }
  
  // Solana staking rewards
  async trackSolanaRewards(walletAddress: string, since: Date): Promise<StakingReward[]> {
    // Используем Solana RPC getInflationReward
    const connection = new Connection(SOLANA_RPC);
    
    const rewardHistory = await connection.getInflationReward(
      [walletAddress],
      { epoch: await this.getEpochSince(since) }
    );
    
    return rewardHistory.map(r => ({
      timestamp: epochToTimestamp(r.epoch),
      protocol: "Solana Staking",
      asset: "SOL",
      amount: r.amount / 1e9, // lamports → SOL
      usdValue: (r.amount / 1e9) * solPriceAtEpoch,
    }));
  }
}

Сводный отчёт по стейкингу

async function generateStakingTaxReport(
  userId: string,
  taxYear: number,
  jurisdiction: string
): Promise<StakingTaxReport> {
  const rewards = await db.getStakingRewards(userId, taxYear);
  
  // Группируем по протоколу и месяцу
  const byProtocol = groupBy(rewards, r => r.protocol);
  const monthly = groupByMonth(rewards);
  
  const totalIncome = rewards.reduce((sum, r) => sum + r.usdValue, 0);
  
  // Для Германии: проверяем Freigrenze €256
  const taxableAmount = jurisdiction === "DE"
    ? Math.max(0, totalIncome - 256)
    : totalIncome;
  
  return {
    taxYear,
    jurisdiction,
    totalRewardsUSD: totalIncome,
    taxableAmountUSD: taxableAmount,
    byProtocol: Object.entries(byProtocol).map(([protocol, rewards]) => ({
      protocol,
      totalRewards: rewards.reduce((sum, r) => sum + r.amount, 0),
      totalUSD: rewards.reduce((sum, r) => sum + r.usdValue, 0),
    })),
    monthlyBreakdown: monthly,
    rewards: rewards.map(r => ({
      ...r,
      costBasisForFutureDisposal: r.usdValue, // cost basis = income value
    })),
  };
}

Особенность: cost basis при будущей продаже

Важный момент: staking reward полученный и включённый в ordinary income создаёт cost basis для будущей продажи. Система должна создавать tax lot:

// При учёте staking reward — создаём lot
await db.createTaxLot({
  userId,
  asset: reward.asset,
  amount: reward.amount,
  costPerUnitUSD: reward.usdValue / reward.amount,
  totalCostUSD: reward.usdValue,
  acquiredAt: reward.timestamp,
  source: "staking_reward",
  acquisitionType: "INCOME", // отличаем от обычной покупки
});

Система учёта staking rewards с поддержкой Lido, ETH2 validator, Solana, Cosmos — 3-4 недели разработки.