Batch Posting

Batch Posting

Compressed Rollup of Matches with Merkleized Hash Commitments and Timestamp Attestation

SnarkSide’s on-chain settlement strategy emphasizes minimal on-chain disclosure, maximum verifiability, and scalable batch efficiency. To this end, the protocol implements a batch posting system, whereby multiple matched trades are compressed, committed, and attested on-chain as a single verifiable update. Each batch is a cryptographically bound rollup of multiple match proofs, represented by a Merkle root commitment, and timestamped to anchor it in Ethereum’s block history.

This batch posting mechanism plays a vital role in reducing gas costs, protecting user privacy at scale, and supporting asynchronous trade execution while preserving full cryptographic integrity.


Overview

Batch posting is the act of submitting a Merkle root commitment of multiple matched trade proofs (along with associated metadata) to the SnarkSide settlement contract. This root acts as a succinct cryptographic reference to all matched trades in a given epoch or relayer window.

This mechanism allows SnarkSide to:

  • Compress hundreds or thousands of match events into a single on-chain transaction

  • Eliminate the need to verify every SNARK proof on-chain individually

  • Enable asynchronous match publication and settlement

  • Support cross-chain and L2 proof relay by decoupling execution from matching

Only one thing is submitted on-chain per batch: the root commitment. Everything else — proof data, nullifier usage, vault deltas — is verified off-chain and revealed only as needed during settlement.


Structure of a Batch

Each batch is composed of the following fields:

Field
Description

merkle_root

Poseidon Merkle root of match commitments

timestamp_commitment

Hash of block number + relayer epoch salt

batch_id

Deterministic ID derived from root + timestamp

num_matches

Number of matches included

relayer_signature

BLS or Schnorr signature attesting to batch

proof_metadata[]

[Optional] metadata tags for future queries

Only the merkle_root and timestamp_commitment are stored on-chain. All others are emitted via event logs or off-chain storage.


Merkle Tree Construction

Relayers maintain a local list of all match_commitment hashes constructed from MPC-handshakes and verified via the Match Validity Circuit. Each hash is a bytes32 field resulting from:

match_commitment = Poseidon(intent_commitment_A, intent_commitment_B, match_salt)

Once a matching epoch completes, relayers:

  1. Sort all match_commitments deterministically

  2. Construct a Poseidon Merkle Tree of fixed depth (e.g. 16, 20, 24)

  3. Compute the Merkle root

  4. Hash the root with a timestamp_salt to produce the batch ID

Example (in Circom/Poseidon pseudo-code):

tree_depth = 16
leaves = [match_commitment_0, match_commitment_1, ..., match_commitment_n]
merkle_root = PoseidonMerkleTree(leaves, depth=tree_depth)

timestamp_commitment = Poseidon(merkle_root, block.number, relayer_epoch_salt)

This root acts as a canonical anchor for the set of trades matched during the epoch.


Timestamp Attestation

To ensure time-based consistency and prevent root replays or batch manipulation, SnarkSide binds each batch to the block history via a timestamp commitment.

This is constructed as:

timestamp_commitment = keccak256(abi.encodePacked(
    block.number,
    epoch_salt,
    merkle_root
));

The result is a unique, non-reusable signature of the batch’s submission moment. This is stored in the on-chain registry and emitted in the BatchPosted event.

Relayers are required to sign each batch submission with their BLS key or MPC quorum, proving:

  • Liveness

  • Ordering

  • Fault attribution (in the case of invalid root proofs)


On-Chain Storage and Events

The settlement contract exposes the following method:

function postBatch(
    bytes32 merkleRoot,
    bytes32 timestampCommitment,
    uint256 batchSize,
    bytes calldata relayerSignature
) external {
    require(!batchUsed[merkleRoot], "Batch already posted");
    require(verifySignature(relayerSignature), "Invalid relayer attestation");

    batchUsed[merkleRoot] = true;
    emit BatchPosted(merkleRoot, timestampCommitment, batchSize, block.timestamp);
}

This event forms the canonical reference for off-chain provers, indexers, and light clients to query match validity.


Deferred Proof Inclusion (Lazy Verification)

The batch system supports lazy proof validation. That is, rather than validating all match proofs on-chain during batch submission, proofs can be stored off-chain (IPFS, Arweave, Data Availability layer) and only inclusion-proven when needed.

During settlement of any given trade, the user or relayer provides:

  • match_commitment

  • Merkle proof of inclusion in batch root

  • Original match proof (SNARK)

  • Nullifiers and public inputs

This dramatically reduces on-chain load and enables high-throughput scaling without compromising verifiability.


Advantages

Feature
Benefit

Merkle compression

Reduces on-chain storage and gas

Timestamp attestation

Binds root to Ethereum L1 block history

Stateless submission

Relayers do not require stateful sequencing

Light client verifiability

Enables Merkle proof checks off-chain

Lazy verification

Allows SNARK validation only during settlement

DoS resistance

Prevents large-scale proof spam


Summary

The Batch Posting mechanism in SnarkSide is a key scaling primitive for private matching and settlement. It transforms hundreds of opaque match events into a single, timestamped Merkle root — enabling on-chain efficiency, data availability separation, and cryptographic verifiability at scale.

In essence, it provides the block-level atomicity of a rollup with the privacy and latency of an intent-based dark pool — the perfect execution surface for decentralized derivatives without exposure.

Last updated