跳转到主要内容
测试版:钱包API目前处于测试阶段。API和响应格式可能会更改。

概述

交易历史端点使用增强交易API检索Solana钱包的完整交易历史。返回人类可读的解析交易以及每笔交易的余额变化。分页是手动的 - API每次请求最多返回100笔交易。 按时间逆序返回交易(最新的在前)。 关联的代币账户(ATAs): tokenAccounts 参数控制是否包含涉及钱包拥有的代币账户的交易:
  • balanceChanged(推荐):包含更改代币账户余额的交易,过滤垃圾信息
  • none:仅直接钱包交互
  • all:所有代币账户交易,包括垃圾信息
旧交易的限制tokenAccounts 过滤器依赖于代币余额元数据中的 owner 字段,该字段在插槽111,491,819(约2022年12月)之前不可用。在此插槽之前活跃的代币账户交易可能会丢失。请参阅getTransactionsForAddress教程 以获取解决方法。
分页: 使用 before 参数与 pagination.nextCursor 一起获取下一页。响应包括 pagination.hasMore 以指示是否有更多结果。每次请求进行一次API调用,费用为100个积分。

API参考

查看交易历史的详细API文档

何时使用此功能

当您需要时使用交易历史API:
  • 显示交易记录:向用户展示他们的完整交易历史
  • 计算盈亏:跟踪所有交易的收益和损失
  • 税务与会计:生成完整的交易报告用于报税
  • 投资组合分析:分析交易模式和活动
  • 审计追踪:维护钱包活动的完整记录
  • 余额重建:从历史数据中重建当前余额

快速开始

基本历史查询

获取最新的余额变动交易:
const getTransactionHistory = async (address) => {
  const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();

  console.log(`Found ${data.data.length} transactions`);

  // Display recent transactions
  data.data.forEach(tx => {
    const date = new Date(tx.timestamp * 1000).toLocaleString();
    const status = tx.error ? 'Failed' : 'Success';

    console.log(`\n${status} - ${date}`);
    console.log(`Signature: ${tx.signature.slice(0, 20)}...`);
    console.log(`Fee: ${tx.fee} SOL`);

    // Show balance changes
    tx.balanceChanges.forEach(change => {
      const sign = change.amount > 0 ? '+' : '';
      console.log(`  ${sign}${change.amount} ${change.mint === 'SOL' ? 'SOL' : change.mint.slice(0, 8)}...`);
    });
  });

  return data;
};

getTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");

完整历史的分页

使用分页和参数 before 获取所有交易:
const getAllTransactionHistory = async (address) => {
  let allTransactions = [];
  let before = null;

  do {
    const url = before
      ? `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&before=${before}`
      : `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

    const response = await fetch(url);
    const data = await response.json();

    allTransactions = allTransactions.concat(data.data);
    before = data.pagination.hasMore ? data.pagination.nextCursor : null;

    console.log(`Fetched ${allTransactions.length} transactions so far...`);

  } while (before);

  console.log(`\nTotal transactions: ${allTransactions.length}`);
  return allTransactions;
};

getAllTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");

查询参数

参数类型默认值描述
limitinteger100每次请求的最大交易数(1-100)
beforestring-获取此签名之前的交易(使用上次响应中的 pagination.nextCursor
afterstring-获取此签名之后的交易(用于升序分页)
typestring-按交易类型过滤(例如,SWAP, TRANSFER, NFT_SALE, TOKEN_MINT)
tokenAccountsstringbalanceChanged过滤涉及代币账户的交易:none, balanceChanged(推荐)或 all

可用交易类型

参数 type 支持按以下交易类型过滤: SWAP, TRANSFER, NFT_SALE, NFT_BID, NFT_LISTING, NFT_MINT, NFT_CANCEL_LISTING, TOKEN_MINT, BURN, COMPRESSED_NFT_MINT, COMPRESSED_NFT_TRANSFER, COMPRESSED_NFT_BURN, CREATE_STORE, WHITELIST_CREATOR, ADD_TO_WHITELIST, REMOVE_FROM_WHITELIST, AUCTION_MANAGER_CLAIM_BID, EMPTY_PAYMENT_ACCOUNT, UPDATE_PRIMARY_SALE_METADATA, ADD_TOKEN_TO_VAULT, ACTIVATE_VAULT, INIT_VAULT, INIT_BANK, INIT_STAKE, MERGE_STAKE, SPLIT_STAKE, CREATE_AUCTION_MANAGER, START_AUCTION, CREATE_AUCTION_MANAGER_V2, UPDATE_EXTERNAL_PRICE_ACCOUNT, EXECUTE_TRANSACTION

过滤器示例

// Get only SWAP transactions
const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&type=SWAP`;

响应格式

{
  "data": [
    {
      "signature": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE",
      "timestamp": 1704067200,
      "slot": 250000000,
      "fee": 0.000005,
      "feePayer": "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
      "error": null,
      "balanceChanges": [
        {
          "mint": "So11111111111111111111111111111111111111112",
          "amount": -0.05,
          "decimals": 9
        },
        {
          "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "amount": 50.0,
          "decimals": 6
        }
      ]
    }
  ],
  "pagination": {
    "hasMore": true,
    "nextCursor": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE"
  }
}
对于尚未完全处理的最新交易,timestamp 字段可能是 null

用例

计算总交易量

汇总所有转账以获取交易量:
const calculateTradingVolume = async (address, tokenMint) => {
  const transactions = await getAllTransactionHistory(address);

  let totalVolume = 0;

  transactions.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (change.mint === tokenMint) {
        totalVolume += Math.abs(change.amount);
      }
    });
  });

  console.log(`Total ${tokenMint} volume: ${totalVolume}`);
  return totalVolume;
};

// Example: Calculate total USDC volume
calculateTradingVolume(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC
);

生成税务报告

创建税务申报的交易报告:
const generateTaxReport = async (address, year) => {
  const transactions = await getAllTransactionHistory(address);

  const startDate = new Date(`${year}-01-01`).getTime() / 1000;
  // Set to end of December 31st (23:59:59.999) to include all transactions from that day
  const endDate = new Date(`${year}-12-31T23:59:59.999Z`).getTime() / 1000;

  const taxableTransactions = transactions
    .filter(tx => tx.timestamp >= startDate && tx.timestamp <= endDate)
    .map(tx => ({
      date: new Date(tx.timestamp * 1000).toISOString(),
      signature: tx.signature,
      fee: tx.fee,
      balanceChanges: tx.balanceChanges,
      explorerUrl: `https://orbmarkets.io/tx/${tx.signature}`
    }));

  console.log(`Found ${taxableTransactions.length} transactions in ${year}`);

  // Export as JSON
  const report = {
    address,
    year,
    transactionCount: taxableTransactions.length,
    transactions: taxableTransactions
  };

  console.log(JSON.stringify(report, null, 2));
  return report;
};

generateTaxReport("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY", 2024);

跟踪失败的交易

查找所有失败的交易以了解错误:
const getFailedTransactions = async (address) => {
  const data = await getTransactionHistory(address);

  const failed = data.data.filter(tx => tx.error !== null);

  console.log(`Found ${failed.length} failed transactions`);

  failed.forEach(tx => {
    const date = new Date(tx.timestamp * 1000).toLocaleString();
    console.log(`\n${date}`);
    console.log(`Signature: ${tx.signature}`);
    console.log(`Error: ${tx.error}`);
    console.log(`Fee Paid: ${tx.fee} SOL`);
  });

  return failed;
};

重建历史余额

计算特定时间点的余额:
const getHistoricalBalance = async (address, targetTimestamp) => {
  const transactions = await getAllTransactionHistory(address);

  // Filter to transactions before target date
  const relevantTxs = transactions.filter(tx => tx.timestamp <= targetTimestamp);

  // Sum all balance changes
  const balances = {};

  relevantTxs.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (!balances[change.mint]) {
        balances[change.mint] = 0;
      }
      balances[change.mint] += change.amount;
    });
  });

  console.log(`Historical balances as of ${new Date(targetTimestamp * 1000).toLocaleString()}:`);
  Object.entries(balances).forEach(([mint, balance]) => {
    console.log(`${mint}: ${balance}`);
  });

  return balances;
};

// Example: Get balances on Jan 1, 2024
getHistoricalBalance(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  new Date("2024-01-01").getTime() / 1000
);

分析交易费用

计算支付的总费用:
const analyzeFees = async (address) => {
  const transactions = await getAllTransactionHistory(address);

  const totalFees = transactions.reduce((sum, tx) => sum + tx.fee, 0);
  const avgFee = totalFees / transactions.length;

  const successfulTxs = transactions.filter(tx => !tx.error);
  const failedTxs = transactions.filter(tx => tx.error);

  const wastedFees = failedTxs.reduce((sum, tx) => sum + tx.fee, 0);

  console.log(`Total Transactions: ${transactions.length}`);
  console.log(`Successful: ${successfulTxs.length}`);
  console.log(`Failed: ${failedTxs.length}`);
  console.log(`Total Fees Paid: ${totalFees.toFixed(6)} SOL`);
  console.log(`Average Fee: ${avgFee.toFixed(6)} SOL`);
  console.log(`Wasted on Failed Txs: ${wastedFees.toFixed(6)} SOL`);

  return {
    totalFees,
    avgFee,
    wastedFees,
    successRate: (successfulTxs.length / transactions.length) * 100
  };
};

理解余额变化

每笔交易包括一个数组 balanceChanges,显示钱包持有量的变化:
  • 正数金额 (+):收到的代币
  • 负数金额 (-):发送或消费的代币
  • mint 字段:代币铸币地址(或本地 SOL 使用 "SOL"
  • decimals 字段:代币的小数位数

示例余额变化

// Swap: Sold 0.05 SOL, received 5 USDC
{
  "balanceChanges": [
    { "mint": "SOL", "amount": -0.05, "decimals": 9 },
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": 5.0, "decimals": 6 }
  ]
}

// Simple transfer: Sent 10 USDC
{
  "balanceChanges": [
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": -10.0, "decimals": 6 }
  ]
}

最佳实践

在获取完整交易历史时总是实施分页。某些钱包可能有数十万条交易记录。
历史交易永不变更。将它们缓存到本地,只获取新交易。
检查 error 字段,以区分成功和失败的交易。失败的交易仍然会产生费用。
时间戳以 Unix 秒为单位。转换为本地日期进行显示和过滤。

常见错误

错误代码描述解决方案
400无效的钱包地址格式验证地址是有效的 base58 Solana 地址
401缺少或无效的 API 密钥确保您的 API 密钥包含在请求中
429超出速率限制减少请求频率或升级您的计划

需要帮助?