Skip to main content
An onchain payment is complete when its expected result has executed successfully and the block recording that result is final. The application retrieves the transaction receipt, checks the payment result, and verifies that Simplex consensus has finalized the containing block before crediting a ledger or fulfilling an order. This page verifies onchain outcomes. A Clearing preconfirmation can precede onchain epoch settlement and may have no transaction hash. Use the separate Clearing payment stages for those receipts. A finalized transaction can also place funds in quarantine, so verify the intended recipient credit before marking a payment delivered.

RPC methods

Use the same Metal network for all reads and verify its chain ID against the network configured by your application. See the JSON-RPC reference for request and response formats.

Fields and encodings

These are the raw JSON-RPC encodings. SDKs may decode them into integers or named status values. Decode receipt.blockNumber from hex before comparing it numerically with consensus_status.finalized.number. Compare hashes as bytes or consistently formatted hex strings. The finalized head may have advanced beyond the receipt’s block. Fetch the block at receipt.blockNumber and compare its hash with receipt.blockHash to verify that the transaction belongs to the finalized chain.

Finality check

Require all of the following for the transaction recording the payment result:
  1. The receipt exists and its transaction hash matches the expected transaction.
  2. receipt.status is "0x1".
  3. The receipt’s logs or contract state establish the expected payment result.
  4. receipt.blockNumber <= consensus_status.finalized.number, after decoding both heights.
  5. eth_getBlockByNumber(receipt.blockNumber, false) returns a block whose hash equals receipt.blockHash.
If the block read returns null or an RPC request fails, keep verification pending because the transaction may already have succeeded. Query its original hash to resolve the outcome before creating a new payment transaction.

Block selectors

When checking contract state for a payment, read it at the verified receipt’s block number. This ensures that the state you inspect corresponds to the block recording the payment result.

Payment result checks

Each contract defines the events and state changes that establish its payment result. Use the evidence listed below to verify the intended transfer or hold outcome. When verifying that evidence:
  • Require successful execution and finality for the transaction recording the result
  • Match logs to the expected contract and transaction
  • Compare token amounts as integers in the token’s base units
  • For payments with additional lifecycle steps, verify the final contract outcome required by the payment agreement
Match the event’s token, sender, recipient and amount to the saved payment instruction. For a routed payment, verify the transfer to the final recipient after any intermediate transfers. Use the Event Catalog to interpret the event’s fields. For a shielded payment, also consult the MIP410 hold states and getters and use the private payment data to check that the accepted payment effect matches the intended recipient note and any sender change.

Verification outcomes

Use the observations below to decide whether to keep verification pending, record a failure, or complete the payment in your application. For admission and execution failures, see Error Codes.

Reconciliation and duplicate processing

Save the application’s payment identifier and expected result with the signed transaction and its hash before broadcasting. If the submission response is lost, the saved hash lets you query the original transaction’s outcome and match it to the payment record. Once an event is verified, retain its chain ID, emitting contract, transaction hash, log index, block number, and block hash as the evidence for that payment. The chain ID, transaction hash, and log index together identify the event with a durable key:
Enforce uniqueness on the event key to prevent the same event from being processed twice. Record the verified event and apply its ledger change in the same database transaction so they succeed or fail together. If multiple transaction attempts could fulfill the same payment, also enforce uniqueness on the application payment identifier to prevent separate events from crediting it twice. For MIP410, store the pool contract address and hold ID with the resolution transaction hash. These identifiers connect initiation and resolution to the same application payment record. See Verify and reconcile payments to implement these checks in a server application.

Independent finality verification

The RPC checks rely on the endpoint reporting chain state accurately. To verify finality independently:
  1. Fetch the certificate and header using metal_getFinalityCertificate(blockHash).
  2. Verify the certificate against trusted network parameters and the validator set for its epoch.
  3. Check that the header hashes to the certified block hash.
A verified certificate authenticates the header, which contains the roots needed to verify the payment evidence independently. Check the receipt’s inclusion proof against the header’s receipts root and any contract state proof against its state root. The Finality Certificates reference defines the certificate formats, signature checks, quorum requirements, and current verifier limits used in this process. A null response means the node cannot provide the certificate. This can happen before the certificate has been persisted or after it has been pruned, even for a finalized block.

Verify and reconcile payments

Implement receipt, event, finality, and duplicate-processing checks.

Finality certificates

Verify finalized headers independently of the RPC endpoint.