本指南中讨论的字段和逻辑适用于 Skip Go API 的 /v2/tx/status 端点返回的 JSON 响应对象。有关详细的 schema 信息,请参阅 API Reference。
理解跨链交易及其各个步骤的状态,对于构建清晰且可靠的用户体验至关重要。本指南说明如何解读 /v2/tx/status API 响应中的相关字段,以判断一笔交易及其每个组成转账当前是处理中、已成功、发生错误,还是已被放弃。 这种方式适合驱动应用中的 UI 元素,例如进度指示器、状态消息和错误展示。

/v2/tx/status 响应示例

下面是一个来自 /v2/tx/status 端点的 JSON 响应示例,用于说明本指南中讨论的一些关键字段:
{
  "state": "STATE_COMPLETED_SUCCESS",
  "transfer_sequence": [
    {
      "cctp_transfer": {
        "from_chain_id": "42161",
        "to_chain_id": "8453",
        "state": "CCTP_TRANSFER_RECEIVED",
        "txs": {
          "send_tx": {
            "chain_id": "42161",
            "tx_hash": "0xYOUR_SEND_TRANSACTION_HASH_HERE_...",
            "explorer_link": "https://arbiscan.io/tx/0xYOUR_SEND_TRANSACTION_HASH_HERE_..."
          },
          "receive_tx": {
            "chain_id": "8453",
            "tx_hash": "0xYOUR_RECEIVE_TRANSACTION_HASH_HERE_...",
            "explorer_link": "https://basescan.org/tx/0xYOUR_RECEIVE_TRANSACTION_HASH_HERE_..."
          }
        },
        "src_chain_id": "42161",
        "dst_chain_id": "8453"
      }
    }
  ],
  "next_blocking_transfer": null,
  "transfer_asset_release": {
    "chain_id": "8453",
    "denom": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "amount": "YOUR_EXAMPLE_AMOUNT",
    "released": true
  },
  "error": null
}

状态解读的核心概念

这套逻辑依赖于 /v2/tx/status API 响应对象中通常可获得的几项关键信息:
  1. 整体交易状态: 这提供了整个多步骤操作的高层视图。
    • 查看响应顶层的 state 字段。
    • 可能的取值包括:
      • 'STATE_COMPLETED_SUCCESS':整个交易已成功完成。
      • 'STATE_COMPLETED_ERROR':交易已结束,但过程中发生了错误。
      • 'STATE_ABANDONED':交易已被放弃(例如由于超时或用户操作)。
    • 如果状态不是这些终态之一,通常可以认为交易仍在等待中或执行中。
  2. 下一个阻塞步骤(或失败点): 这表示当前序列中正在执行的是哪一个具体转账,或者是哪一个步骤导致了失败或放弃。
    • 使用 next_blocking_transfer.transfer_sequence_index 字段(如果响应中存在 next_blocking_transfer)。
    • 该值是一个索引,指向顶层 transfer_sequence 数组中的某个操作。
  3. 对序列中的每个操作进行分类: 对于响应中 transfer_sequence 数组内的每个操作,都可以判断其单独状态:
    • 加载中/等待中:
      • 该操作的索引与 next_blocking_transfer.transfer_sequence_index 相同(如果存在 next_blocking_transfer)。
      • 并且整体交易仍在进行中(即顶层 state 不是 STATE_COMPLETED_ERROR 或 STATE_ABANDONED)。
    • 错误/失败/已放弃:
      • 该操作的索引与 next_blocking_transfer.transfer_sequence_index 相同(如果存在 next_blocking_transfer。通常当整体 state 已经是终态时,它会是 null,例如 STATE_COMPLETED_SUCCESS、STATE_COMPLETED_ERROR 或 STATE_ABANDONED,因为此时交易已不再被主动阻塞,或已经成功结束)。
      • 并且整体交易状态(顶层 state 字段)为 STATE_COMPLETED_ERROR 或 STATE_ABANDONED。
      • 此外,如果整体交易状态为 STATE_COMPLETED_ERROR,并且这是序列中的最后一个操作,那么它也应视为处于错误状态。
      • 注意: 如果整体交易 state 为 STATE_COMPLETED_ERROR,还必须检查 transfer_sequence 中每个单独转账步骤里的具体 error 对象(例如 step.ibc_transfer.packet_txs.error、step.cctp_transfer.error 等)。这有助于准确定位到底是哪一段流程出了问题,因为当交易进入终态错误,而不是中途卡住时,next_blocking_transfer 可能会是 null。
    • 成功:
      • 如果整体交易状态(顶层 state 字段)为 STATE_COMPLETED_SUCCESS,那么序列中的所有操作都应视为成功。
      • 如果整体交易仍在进行中,或者已经失败/被放弃,那么位于 next_blocking_transfer.transfer_sequence_index 之前的任何操作(如果存在 next_blocking_transfer,见上文关于它在终态下通常为 null 的说明)都可以视为已成功完成。

示例实现逻辑(JavaScript)

下面的 JavaScript 代码片段演示了如何将这些概念转化为代码,以判断每个步骤的状态。
// Assume 'transfer' is the main transaction object from our API
// and 'totalSteps' is the length of transfer.transfer_sequence

// 1. Determine overall transaction status from the main transaction object
const isTransactionSuccessful = transfer.state === 'STATE_COMPLETED_SUCCESS';
const isTransactionFailed = transfer.state === 'STATE_COMPLETED_ERROR';
const isTransactionAbandoned = transfer.state === 'STATE_ABANDONED';

// 2. Get the index of the step that is currently blocking progress or has failed
const nextBlockingIndex = transfer.next_blocking_transfer?.transfer_sequence_index;

// Then, when we process each 'step' in the 'transfer.transfer_sequence' at a given 'index':
// (This logic would typically be inside a loop, e.g., transfer.transfer_sequence.forEach((step, index) => { ... }))

// 3. Categorize the current step:

// Is this step currently "pending" (loading)?
const isStepPending = index === nextBlockingIndex && 
                      !isTransactionFailed && 
                      !isTransactionAbandoned;

// Is this step in an "error" state (or part of an abandoned flow)?
// 'totalSteps' would be transfer.transfer_sequence.length
const isStepAbandonedOrFailed = (isTransactionAbandoned || isTransactionFailed) && 
                                (index === nextBlockingIndex || (index === totalSteps - 1 && isTransactionFailed));

// If 'isTransactionSuccessful' is true, this step is part of an overall successful transaction.
// If a step isn't 'isStepPending' and isn't 'isStepAbandonedOrFailed', 
// and its 'index < nextBlockingIndex' (for an ongoing or failed tx), it's also implicitly a success.

// These boolean flags (isStepPending, isStepAbandonedOrFailed, isTransactionSuccessful)
// are then used to drive the UI styling for that specific step (e.g., node color, edge animation, icons).
// For example:
// if (isStepAbandonedOrFailed) { /* show error UI */ }
// else if (isStepPending) { /* show loading UI */ }
// else { /* show success UI (either part of overall success, or completed before a pending/error state) */ }
通过基于这些字段和状态实现相应逻辑,你就可以向用户准确、及时地反馈其跨链交易的进度。

理解资产释放(transfer_asset_release)

/v2/tx/status 响应中的 transfer_asset_release 对象提供了关键信息,用于说明用户资产最终落在什么位置,或者预计可以在哪里领取,尤其适用于涉及兑换或复杂路由的场景。 关键字段包括:
  • chain_id:资产所在的链 ID。
  • denom:已释放资产的面额(资产标识符)。
  • amount:已释放资产的数量。
  • released:一个布尔值,用于表示资产是否已经被明确释放给用户(例如已经出现在钱包中,或可以领取)。如果为 false,则可能表示资产仍在合约中,或仍需等待最后一步才能释放。
当跨链兑换失败时,transfer_asset_release 字段对于判断用户资金的位置和状态尤为重要。若想全面了解在不同失败场景下(例如兑换前失败与兑换后失败)资产会如何处理,请参阅我们的详细指南:Handling Cross-Chain Failure Cases。
The fields and logic discussed in this guide pertain to the JSON response object from the /v2/tx/status endpoint of the Skip Go API. Refer to the API Reference for detailed schema information.
Understanding the status of a cross-chain transaction and its individual steps is crucial for building a clear and reliable user experience. This guide explains how to interpret the relevant fields from the /v2/tx/status API response to determine if a transaction (and each of its constituent transfers) is pending, successful, has encountered an error, or has been abandoned. This approach is useful for driving UI elements such as progress indicators, status messages, and error displays in your application.

Example /v2/tx/status Response

Below is an example of a JSON response from the /v2/tx/status endpoint, illustrating some of the key fields discussed in this guide:
{
  "state": "STATE_COMPLETED_SUCCESS",
  "transfer_sequence": [
    {
      "cctp_transfer": {
        "from_chain_id": "42161",
        "to_chain_id": "8453",
        "state": "CCTP_TRANSFER_RECEIVED",
        "txs": {
          "send_tx": {
            "chain_id": "42161",
            "tx_hash": "0xYOUR_SEND_TRANSACTION_HASH_HERE_...",
            "explorer_link": "https://arbiscan.io/tx/0xYOUR_SEND_TRANSACTION_HASH_HERE_..."
          },
          "receive_tx": {
            "chain_id": "8453",
            "tx_hash": "0xYOUR_RECEIVE_TRANSACTION_HASH_HERE_...",
            "explorer_link": "https://basescan.org/tx/0xYOUR_RECEIVE_TRANSACTION_HASH_HERE_..."
          }
        },
        "src_chain_id": "42161",
        "dst_chain_id": "8453"
      }
    }
  ],
  "next_blocking_transfer": null,
  "transfer_asset_release": {
    "chain_id": "8453",
    "denom": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "amount": "YOUR_EXAMPLE_AMOUNT",
    "released": true
  },
  "error": null
}

Core Concepts for Status Interpretation

The logic relies on a few key pieces of information typically available in the /v2/tx/status API response object:
  1. The Overall Transaction Status: This provides a high-level view of the entire multi-step operation.
    • Look at the top-level state field in the response.
    • Possible values include:
      • 'STATE_COMPLETED_SUCCESS': The entire transaction finished successfully.
      • 'STATE_COMPLETED_ERROR': The transaction finished, but an error occurred.
      • 'STATE_ABANDONED': The transaction was abandoned (e.g., due to timeout or user action).
    • If the state is not one of these terminal states, it’s generally assumed to be pending or in progress.
  2. The Next Blocking Step (or Failure Point): This indicates which specific transfer in the sequence is currently active, or which one caused a failure or abandonment.
    • Utilize the next_blocking_transfer.transfer_sequence_index field (if next_blocking_transfer exists in the response).
    • This will be an index pointing to an operation within the top-level transfer_sequence array.
  3. Categorizing Each Operation in the Sequence: For each operation within the transfer_sequence array of the response, you can determine its individual status:
    • Loading/Pending:
      • The operation’s index matches the next_blocking_transfer.transfer_sequence_index (if next_blocking_transfer exists).
      • AND the overall transaction is still in progress (i.e., the top-level state is not STATE_COMPLETED_ERROR or STATE_ABANDONED).
    • Error/Failed/Abandoned:
      • The operation’s index matches the next_blocking_transfer.transfer_sequence_index (if next_blocking_transfer exists - it is typically null if the overall state is terminal (e.g., STATE_COMPLETED_SUCCESS, STATE_COMPLETED_ERROR, or STATE_ABANDONED) as the transaction is no longer actively blocked or has finished successfully).
      • AND the overall transaction state (the top-level state field) is STATE_COMPLETED_ERROR or STATE_ABANDONED.
      • Additionally, if the overall transaction state is STATE_COMPLETED_ERROR and this is the last operation in the sequence, it is also considered to be in an error state.
      • Note: If the overall transaction state is STATE_COMPLETED_ERROR, it’s also crucial to inspect the specific error object within each individual transfer step in the transfer_sequence (e.g., step.ibc_transfer.packet_txs.error, step.cctp_transfer.error, etc.). This will help pinpoint the exact leg(s) that encountered issues, as the next_blocking_transfer might be null if the transaction reached a terminal error state rather than getting stuck midway.
    • Success:
      • If the overall transaction state (top-level state field) is STATE_COMPLETED_SUCCESS, then all operations in the sequence are considered successful.
      • If the overall transaction is still in progress, or has failed/been abandoned, any operation before the next_blocking_transfer.transfer_sequence_index (if next_blocking_transfer exists - see note above about it typically being null in terminal states) is assumed to have completed successfully.

Example Implementation Logic (JavaScript)

The following JavaScript snippet demonstrates how these concepts can be translated into code to determine the status of each step.
// Assume 'transfer' is the main transaction object from our API
// and 'totalSteps' is the length of transfer.transfer_sequence

// 1. Determine overall transaction status from the main transaction object
const isTransactionSuccessful = transfer.state === 'STATE_COMPLETED_SUCCESS';
const isTransactionFailed = transfer.state === 'STATE_COMPLETED_ERROR';
const isTransactionAbandoned = transfer.state === 'STATE_ABANDONED';

// 2. Get the index of the step that is currently blocking progress or has failed
const nextBlockingIndex = transfer.next_blocking_transfer?.transfer_sequence_index;

// Then, when we process each 'step' in the 'transfer.transfer_sequence' at a given 'index':
// (This logic would typically be inside a loop, e.g., transfer.transfer_sequence.forEach((step, index) => { ... }))

// 3. Categorize the current step:

// Is this step currently "pending" (loading)?
const isStepPending = index === nextBlockingIndex && 
                      !isTransactionFailed && 
                      !isTransactionAbandoned;

// Is this step in an "error" state (or part of an abandoned flow)?
// 'totalSteps' would be transfer.transfer_sequence.length
const isStepAbandonedOrFailed = (isTransactionAbandoned || isTransactionFailed) && 
                                (index === nextBlockingIndex || (index === totalSteps - 1 && isTransactionFailed));

// If 'isTransactionSuccessful' is true, this step is part of an overall successful transaction.
// If a step isn't 'isStepPending' and isn't 'isStepAbandonedOrFailed', 
// and its 'index < nextBlockingIndex' (for an ongoing or failed tx), it's also implicitly a success.

// These boolean flags (isStepPending, isStepAbandonedOrFailed, isTransactionSuccessful)
// are then used to drive the UI styling for that specific step (e.g., node color, edge animation, icons).
// For example:
// if (isStepAbandonedOrFailed) { /* show error UI */ }
// else if (isStepPending) { /* show loading UI */ }
// else { /* show success UI (either part of overall success, or completed before a pending/error state) */ }
By implementing logic based on these fields and states, you can provide users with accurate and timely feedback on the progress of their cross-chain transactions.

Understanding Asset Release (transfer_asset_release)

The transfer_asset_release object in the /v2/tx/status response provides crucial information about where the user’s assets have ultimately landed or are expected to be claimable, especially in scenarios involving swaps or complex routes. Key fields include:
  • chain_id: The chain ID where the assets are located.
  • denom: The denomination (asset identifier) of the released assets.
  • amount: The quantity of the released assets.
  • released: A boolean indicating if the assets have been definitively released to the user (e.g., available in their wallet or claimable). If false, it might indicate that assets are still in a contract or awaiting a final step for release.
In the event of a cross-chain swap failure, the transfer_asset_release field is particularly important for determining the location and state of the user’s funds. For a comprehensive understanding of how assets are handled in different failure scenarios (e.g., pre-swap vs. post-swap failures), please refer to our detailed guide on Handling Cross-Chain Failure Cases.