PrivacyPool::constructor
├── Given valid addresses
│   ├── It sets asset address
│   ├── It sets verifier address
│   ├── It sets entrypoint address
│   ├── It computes scope from contract, chain id and asset
│   └── It initializes base state contract
└── When any address is zero
    └── It reverts with ZeroAddress

PrivacyPool::deposit
├── Given caller is entrypoint
│   ├── Given pool is active
│   │   ├── When depositing valid value and commitment
│   │   │   ├── It increments global nonce
│   │   │   ├── It computes label as keccak of scope and nonce
│   │   │   ├── It maps label to depositor address
│   │   │   ├── It computes commitment hash correctly
│   │   │   ├── It inserts commitment in merkle tree
│   │   │   ├── It handles asset transfer
│   │   │   └── It emits Deposited event
│   │   ├── When depositing zero value
│   │   │   └── It processes deposit normally
│   │   ├── When commitment exists in tree
│   │   │   └── It reverts with LeafAlreadyExists
│   │   └── When deposit value is greater than 2**128
│   │       └── It reverts with InvalidDepositValue 
│   └── When pool is dead
│       └── It reverts with PoolIsDead
└── When caller is not entrypoint
    └── It reverts with OnlyEntrypoint

PrivacyPool::withdraw
├── Given caller is processooor
│   ├── Given valid proof
│   │   ├── Given known state root
│   │   │   ├── Given latest ASP root
│   │   │   │   ├── Given valid tree depths
│   │   │   │   │   ├── When withdrawing nonzero amount
│   │   │   │   │   │   ├── It verifies proof with verifier
│   │   │   │   │   │   ├── It spends nullifier hash
│   │   │   │   │   │   ├── It inserts new commitment
│   │   │   │   │   │   ├── It transfers value to processooor
│   │   │   │   │   │   └── It emits Withdrawn event
│   │   │   │   │   └── When nullifier already spent
│   │   │   │   │       └── It reverts with NullifierAlreadySpent
│   │   │   │   └── When tree depths exceed maximum
│   │   │   │       └── It reverts with InvalidTreeDepth
│   │   │   └── When ASP root is outdated
│   │   │       └── It reverts with IncorrectASPRoot
│   │   └── When state root unknown
│   │       └── It reverts with UnknownStateRoot
│   └── When proof context mismatches
│       └── It reverts with ContextMismatch
└── When caller is not processooor
    └── It reverts with InvalidProcessooor

PrivacyPool::ragequit
├── Given caller is original depositor
│   ├── Given commitment exists in state
│   │   ├── When nullifier not spent
│   │   │   ├── It verifies the proof
│   │   │   ├── It marks nullifier as spent
│   │   │   ├── It transfers value to depositor
│   │   │   └── It emits Ragequit event
│   │   └── When nullifier already spent
│   │       └── It reverts with NullifierAlreadySpent
│   └── When commitment not in state
│       └── It reverts with InvalidCommitment
└── When caller is not original depositor
    └── It reverts with OnlyOriginalDepositor

PrivacyPool::windDown
├── Given caller is entrypoint
│   ├── Given pool is active
│   │   ├── It sets dead to true
│   │   └── It emits PoolDied event
│   └── When pool is already dead
│       └── It reverts with PoolIsDead
└── When caller is not entrypoint
    └── It reverts with OnlyEntrypoint
