Smart Contracts

ShieldFlow's smart contracts implement the Privacy Pool protocol with UUPS upgradeability, AccessControl, and Groth16 ZK proof verification.

Deployed Addresses

ContractSepolia Address
Entrypoint0xCFFf9d27e6A23C94447cEA72DDf6B0C3807F5fE5
ETH Pool0xd600BFEdF8E6cEF5c144997BF29137853618D9f3
USDC Pool0x89234FE6d2722fAD5Fde884C618C05EE5568B84e
WithdrawalVerifier0x14df42045c3c128f0dbc7c0ae8a6eee19d678acd
CommitmentVerifier0x213fe14bc0a6c6e1ff909219e2f0dd83c4012b8f

Contract Architecture

Entrypoint (UUPS Upgradeable)

Main entry point for deposits and relayed withdrawals. Acts as the gateway to all pool interactions, routing calls to the appropriate pool contracts. Manages protocol-level configuration including fee rates and pool registration.

Roles: OWNER_ROLE, ASP_POSTMAN
Key Functions: deposit(), relay(), updateRoot(), registerPool()

PrivacyPool (Abstract)

Base contract implementing core deposit and withdrawal logic. Maintains the state Merkle tree (LeanIMT), tracks spent nullifiers to prevent double-spending, and stores a 64-entry circular root history buffer for proof verification against recent tree states.

PrivacyPoolSimple

Concrete implementation for native ETH deposits and withdrawals. Extends PrivacyPool with ETH-specific transfer logic using low-level calls for gas efficiency.

PrivacyPoolComplex

Concrete implementation for ERC-20 token deposits and withdrawals. Extends PrivacyPool with SafeERC20 for secure token transfers, supporting any standard ERC-20 token.

Verifier Contracts

Auto-generated Groth16 proof verification contracts for the withdrawal and commitment circuits. These verify zero-knowledge proofs on-chain to validate withdrawal eligibility without revealing deposit details.

Key Functions

The primary contract interfaces for deposits, withdrawals, and emergency exits:

IEntrypoint.sol
// Deposit ETH
function deposit(uint256 _precommitment) external payable;

// Deposit ERC20
function deposit(IERC20 _asset, uint256 _value, uint256 _precommitment) external;

// Relay withdrawal (called by relayer)
function relay(
    IPrivacyPool.Withdrawal memory _withdrawal,
    ProofLib.WithdrawProof memory _proof,
    uint256 _poolScope
) external;

// Emergency exit (called by original depositor)
function ragequit(ProofLib.CommitmentProof memory _proof) external;

Security Features

UUPS Upgrade Pattern

Controlled upgradeability with authorization checks. Only the contract owner can authorize upgrades, and the implementation logic lives in the proxy itself to prevent unauthorized upgrades.

AccessControl Roles

Fine-grained permission system using OpenZeppelin AccessControl. OWNER_ROLE manages protocol configuration, ASP_POSTMAN updates association set roots.

ReentrancyGuard

Prevents reentrant calls to state-modifying functions. Applied to all deposit, withdrawal, and ragequit operations.

Checks-Effects-Interactions

All state changes (effects) are performed before external calls (interactions). Nullifiers are marked as spent before transferring funds.

SafeERC20

Uses OpenZeppelin SafeERC20 for all ERC-20 token interactions, protecting against non-standard token implementations that don't return boolean values.

Nullifier Tracking

Every withdrawal produces a unique nullifier that is stored on-chain. Attempting to reuse a nullifier reverts the transaction, preventing double-spending.

Root History Buffer (64 entries)

The contract maintains a circular buffer of the last 64 Merkle roots. Withdrawal proofs can reference any recent root, allowing transactions to succeed even when new deposits update the tree between proof generation and on-chain submission.

Solidity Version

Contracts are built with Solidity 0.8.28 using Foundry. Built-in overflow/underflow protection is enabled.