Introduction

On October 21, 2024, zkSecurity was tasked with auditing Renegade’s atomic settlement feature. The specific code to review was shared via public GitHub repositories. The audit lasted five days with one consultant.

Written specifications detailing the circuits, the smart contracts of the atomic settlement feature were also shared.

The code was well commented and was found to be of great quality. The Renegade team was very responsive and helpful in providing additional context.

Scope

The scope of the audit included the circuits and contracts of the atomic settlement feature. zkSecurity used the zksecurity-audit-10-21-24 branch for renegade (commit 1934f69c6cbb290f7536809ff63bb6068ba1028b) and renegade-contracts (commit f7b7dced3fae359185690dff7e63c356b7d6effb).

Renegade circuit:

  1. The circuit constraints for the new NP statement: VALID MATCH SETTLE ATOMIC (zk_circuits/valid_match_settle_atomic.rs).

  2. The logic to link VALID MATCH SETTLE ATOMIC proof to the other proofs of VALID COMMITMENTS (zk_circuits/proof_linking.rs#L274-L363).

Renedage contracts: 1. Darkpool Entrypoint (contracts/darkpool.rs#L542-L571) for process_atomic_match_settle. 2. The core settlement contract (contracts/core/core_settlement.rs): responsible for state updates and routing to other smart contracts for settlement specific calls. 3. The new transfer logic (contracts/transfer_executor.rs#L159): responsible for executing direct ERC20 transfer and transferFrom calls. 4. The settlement verifier contract (contracts/verifier/verifier_settlement.rs#L28): responsible for setting up batch verification and proof-linking elements before passing onto the verifier core.

Overview of Renegade’s Atomic Settlement Feature

Renegade is a dark pool trading platform that allows users to trade ERC-20 assets without revealing any information about their trades and balances. Previously, a user needs to deposit, place an order, match, and withdraw to perform a trade, which was non-atomic. The atomic settlement feature enables an external party to swap with the dark pool in one transaction, without the need to deposit in advance. This can be helpful for certain integrators, such as CoW Swap solvers.

This is the high level flow of atomic settlement:

  1. The external party queries the /request-external-match endpoint on the relayer with their intended trade intention.

  2. The relayer queries its internal pool to find any matches. If a match is found, the relayer returns a ZKP proof for VALID MATCH SETTLE ATOMIC, which includes the matching result (e.g., match amount and price).

  3. The external party receives the proof and statement. If it meets the requirements, the external party calls the contract to perform the swap. The contract then verifies the proof, transfers in the sell token, and transfers out the buy token in a single transaction.

The atomic match circuit functions similarly to the previous internal match circuit. The difference is that the atomic match circuit only verifies the state of one internal party, leaving the external party’s token transfer for the contract to execute.

The circuit ensures that the ExternalMatchResult in the statement is valid. To confirm a valid wallet state transition, the proof is linked with a valid commitment witness, which in turn is linked to a valid reblind witness to ensure the wallet is reblinded from an existing wallet.

wallet

In the contract, the proof is first verified to ensure a valid internal transition. Then, the sell token is transferred from the external party into the pool, and the buy token is transferred to the external party.