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:
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:
Sort all
match_commitmentsdeterministicallyConstruct a Poseidon Merkle Tree of fixed depth (e.g. 16, 20, 24)
Compute the Merkle root
Hash the root with a
timestamp_saltto 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_commitmentMerkle 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
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

