Paxeer Docs logo

Signed Receipts

Learn how LayerX signed receipts, domain-separated Merkle leaves, and inclusion proofs let anyone verify transfers without trusting the sequencer.

Signed receipts

Every transfer on LayerX produces a signed receipt - a cryptographically verifiable record that the transfer occurred, was accepted by the sequencer, and was included in a committed batch. Receipts are the foundation of LayerX's trust model: they let any party verify transfers without relying on the sequencer's honesty.

Receipt structure

A receipt contains:

FieldDescription
seqMonotonically increasing sequence number
senderSender's DID
recipientRecipient's DID
amountTransfer amount in USDX
timestampSequencer-accepted time (RFC 3339)
batch_seqBatch sequence number (set after batch closes)
merkle_leafDomain-separated hash of the transfer
signatureSequencer's Ed25519 signature over the receipt

The sequencer signs every receipt at transfer time. The batch_seq and merkle_leaf fields are populated once the transfer is included in a closed batch.

Domain-separated Merkle leaves

Each transfer is hashed into a Merkle leaf using a domain separator to prevent cross-chain and cross-domain replay:

leaf = keccak256(
  "LAYERX_TRANSFER_V1" ||
  sender_did_bytes ||
  recipient_did_bytes ||
  amount_bytes ||
  seq_bytes ||
  timestamp_bytes
)

The domain separator "LAYERX_TRANSFER_V1" is a fixed string. If LayerX ever introduces a second domain (e.g., for a different asset), it will use a distinct separator.

Inclusion proofs

After a batch is anchored to Paxeer L1, anyone can verify that a specific transfer was included in that batch using a Merkle inclusion proof.

An inclusion proof consists of:

  • The transfer's Merkle leaf.
  • The sibling hashes along the path from the leaf to the root.
  • The expected Merkle root (published on L1).

To verify:

  1. Hash the leaf with its sibling at each level, moving up the tree.
  2. Compare the computed root with the on-chain Merkle root.
  3. If they match, the transfer was included in the batch.
import { verifyInclusion } from "@paxeer/merkle";

const valid = verifyInclusion({
  leaf: transfer.merkle_leaf,
  proof: transfer.merkle_proof,
  root: batch.merkle_root
});
// valid === true means the transfer was committed to L1

Public receipt access

Receipts are publicly readable. Any party can fetch a receipt by its sequence number:

curl https://layerx.paxeer.network/v1/receipt/12345

Response:

{
  "seq": 12345,
  "sender": "did:ed25519:agent.scanner.v1",
  "recipient": "did:ed25519:service.weather.v2",
  "amount": "0.001",
  "timestamp": "2026-01-15T10:03:42Z",
  "batch_seq": 987,
  "merkle_leaf": "0xa3f9...",
  "merkle_proof": ["0xb2c1...", "0xd4e5..."],
  "signature": "base64url-encoded-sequencer-signature"
}

This endpoint is unauthenticated - no DID challenge or principal token required. Receipts are public records.

Independent verifiability

The receipt system is designed so that no party needs to trust the sequencer:

  • Recipients verify that their incoming transfer was signed by the sequencer and included in a committed batch.
  • Senders verify that their outgoing transfer was recorded correctly.
  • Third parties (auditors, regulators, other agents) can verify any transfer's inclusion by checking the Merkle proof against the on-chain root.
  • The sequencer cannot forge transfers - the Merkle root on L1 is immutable once anchored, and any discrepancy between the API's receipts and the on-chain root would be immediately detectable.

This model ensures that LayerX's off-chain speed does not compromise on-chain verifiability.