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

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы учета NFT-операций для налогов
Сложная
~1-2 недели
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • 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

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

NFT налогообложение — спорная область с юрисдикционными различиями. В США IRS трактует NFT как property (capital asset) — продажа = capital gain/loss. Minting из collection — cost basis = gas fee + mint price. Royalties = ordinary income. Бесплатные drops — income по FMV при получении.

Специфика NFT учёта

Отличие от fungible tokens: каждый NFT уникален. Cost basis для конкретного #1234 из collection — цена именно этого токена, не средняя по collection.

Floor price vs sale price: налоговая база при получении бесплатного NFT — fair market value. Это обычно floor price на момент mint/receipt. Проблема: floor price волатилен, и для редких трейтов реальная стоимость выше floor.

Wash trading: покупка и продажа NFT самому себе для искусственного завышения цены — налоговое мошенничество.

Схема данных

interface NFTTaxRecord {
  tokenAddress: string;
  tokenId: string;
  collectionName: string;
  
  // Acquisition
  acquiredAt: Date;
  acquiredFrom: string;     // address или "mint"
  acquisitionType: "MINT" | "PURCHASE" | "AIRDROP" | "GIFT" | "TRANSFER_IN";
  acquisitionPrice: number; // в ETH
  gasAtAcquisition: number;
  costBasisUSD: number;     // acquisitionPrice + gas (в USD по курсу)
  
  // Disposition
  disposedAt?: Date;
  disposedTo?: string;
  dispositionType?: "SALE" | "GIFT" | "BURN" | "TRANSFER_OUT";
  salePrice?: number;
  royaltyPaid?: number;     // royalty fee для creator
  gasAtDisposition?: number;
  proceedsUSD?: number;     // salePrice - royalty - gas (в USD)
  
  // P&L
  realizedGainUSD?: number; // proceedsUSD - costBasisUSD
  isLongTerm?: boolean;
  
  // Royalties received (если owner является creator)
  royaltiesReceived?: RoyaltyPayment[];
}

Импорт NFT транзакций

class NFTTransactionImporter {
  async importNFTHistory(walletAddress: string): Promise<NFTTaxRecord[]> {
    // Используем Moralis / Alchemy для NFT transfer history
    const nftTransfers = await this.moralis.getNFTTransfers(walletAddress);
    
    const records: NFTTaxRecord[] = [];
    
    for (const transfer of nftTransfers) {
      const isReceive = transfer.to.toLowerCase() === walletAddress.toLowerCase();
      const isSend = transfer.from.toLowerCase() === walletAddress.toLowerCase();
      
      if (isReceive) {
        // Получение NFT
        const record = await this.processNFTReceive(transfer, walletAddress);
        records.push(record);
      }
      
      if (isSend) {
        // Передача/продажа NFT
        const existingRecord = await this.db.getNFTRecord(
          transfer.tokenAddress, transfer.tokenId, walletAddress
        );
        if (existingRecord) {
          await this.processNFTDisposal(existingRecord, transfer);
        }
      }
    }
    
    return records;
  }
  
  private async processNFTReceive(
    transfer: NFTTransfer,
    walletAddress: string
  ): Promise<NFTTaxRecord> {
    // Определяем тип получения
    const isMint = transfer.from === "0x0000000000000000000000000000000000000000";
    
    // Получаем цену из transaction value или marketplace event
    const { price, royalty } = await this.extractPriceFromTx(transfer.txHash);
    
    // Получаем FMV для бесплатных mint/airdrop
    let costBasisUSD: number;
    if (price > 0) {
      const ethPrice = await this.priceService.getHistoricalPrice("ETH", transfer.timestamp);
      costBasisUSD = price * ethPrice + transfer.gasUsed * transfer.gasPrice * ethPrice / 1e18;
    } else {
      // Бесплатный mint/airdrop — FMV по floor price
      const floorPrice = await this.getFloorPriceAtTime(transfer.tokenAddress, transfer.timestamp);
      costBasisUSD = floorPrice;
    }
    
    return {
      tokenAddress: transfer.tokenAddress,
      tokenId: transfer.tokenId,
      collectionName: transfer.collectionName,
      acquiredAt: transfer.timestamp,
      acquiredFrom: transfer.from,
      acquisitionType: isMint ? "MINT" : price > 0 ? "PURCHASE" : "AIRDROP",
      acquisitionPrice: price,
      gasAtAcquisition: transfer.gasUsed * transfer.gasPrice / 1e18,
      costBasisUSD,
    };
  }
}

Floor price источники

class NFTFloorPriceService {
  async getFloorPriceAtTime(collectionAddress: string, timestamp: Date): Promise<number> {
    // Reservoir Protocol для исторических floor prices
    const response = await fetch(
      `https://api.reservoir.tools/collections/${collectionAddress}/floor-ask?timestamp=${timestamp.getTime() / 1000}`,
      { headers: { "x-api-key": RESERVOIR_API_KEY } }
    );
    
    const data = await response.json();
    const ethPrice = await this.priceService.getHistoricalPrice("ETH", timestamp);
    
    return (data.price?.amount?.native ?? 0) * ethPrice;
  }
}

Royalty учёт для creators

async function trackRoyaltyIncome(creatorAddress: string): Promise<RoyaltyIncome[]> {
  // Находим все ERC-2981 royalty payments из событий
  const royaltyLogs = await getERC2981RoyaltyPayments(creatorAddress);
  
  return Promise.all(royaltyLogs.map(async log => {
    const ethPrice = await priceService.getHistoricalPrice("ETH", log.timestamp);
    
    return {
      timestamp: log.timestamp,
      collection: log.tokenAddress,
      tokenId: log.tokenId,
      amountETH: log.royaltyAmount / 1e18,
      valueUSD: (log.royaltyAmount / 1e18) * ethPrice,
      taxCategory: TaxCategory.ROYALTY_INCOME, // ordinary income
      txHash: log.txHash,
    };
  }));
}

Сводная отчётность

async function generateNFTTaxSummary(
  userId: string,
  taxYear: number
): Promise<NFTTaxSummary> {
  const [sales, royalties] = await Promise.all([
    db.getNFTSales(userId, taxYear),
    db.getNFTRoyalties(userId, taxYear),
  ]);
  
  const shortTermGains = sales.filter(s => !s.isLongTerm)
    .reduce((sum, s) => sum + s.realizedGainUSD, 0);
  const longTermGains = sales.filter(s => s.isLongTerm)
    .reduce((sum, s) => sum + s.realizedGainUSD, 0);
  const royaltyIncome = royalties.reduce((sum, r) => sum + r.valueUSD, 0);
  
  return {
    taxYear,
    nftSalesCount: sales.length,
    shortTermGains,
    longTermGains,
    royaltyIncome,
    totalTaxableEvents: shortTermGains + longTermGains + royaltyIncome,
    saleDetails: sales,
    royaltyDetails: royalties,
  };
}

Стек

Компонент Технология
NFT data Moralis + Alchemy NFT API
Floor prices Reservoir Protocol API
Sales detection Seaport events + Blur events
Price history CoinGecko ETH
Storage PostgreSQL

NFT tax accounting система с import, floor price tracking, royalty income и мультиюрисдикционными отчётами: 4-6 недель разработки.