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:
| Field | Description |
|---|---|
seq | Monotonically increasing sequence number |
sender | Sender's DID |
recipient | Recipient's DID |
amount | Transfer amount in USDX |
timestamp | Sequencer-accepted time (RFC 3339) |
batch_seq | Batch sequence number (set after batch closes) |
merkle_leaf | Domain-separated hash of the transfer |
signature | Sequencer'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:
- Hash the leaf with its sibling at each level, moving up the tree.
- Compare the computed root with the on-chain Merkle root.
- 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.