> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useabyss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdrawal Flow

> Defines how private value exits Abyss through zero-knowledge authorization without reintroducing address-level linkage.

The withdrawal flow is where Abyss’s privacy guarantees are actually realized. Unlike deposits, which are publicly observable by necessity, withdrawals are designed to be **cryptographically unlinkable** to any prior on-chain activity. The protocol enforces this unlinkability not through heuristics or delay, but through zero-knowledge proofs that replace identity with knowledge.

Conceptually, a withdrawal performs the inverse of a deposit, but without symmetry at the graph level:

```
(Commitment, Secret, Proof)
        ↓
(Recipient Address, Amount)
```

The critical distinction is that the protocol never learns *which* commitment is being spent, only that **some valid commitment exists** and that the withdrawal is authorized.

***

### V.2.1 Withdrawal Preconditions

To initiate a withdrawal, a user must possess:

* The original `secret_key`
* An unused withdrawal index `i`
* A Merkle root corresponding to a valid pool state

No address-level permission is required. The withdrawal can be initiated by any address, including relayers, merchants, or third parties acting on behalf of the user.

***

### V.2.2 Nullifier Generation

Each withdrawal consumes a unique nullifier derived deterministically from the secret:

```
nullifier_i := H(secret_key || i)
```

This nullifier serves as a one-time marker that prevents double-spending. It reveals nothing about the commitment or the secret itself, but it is globally unique per withdrawal index.

On-chain, the protocol maintains:

```
NullifierSet := { N₁, N₂, … }
```

Any attempt to reuse a nullifier results in a hard revert.

***

### V.2.3 Proof Construction

The client constructs a zero-knowledge proof asserting the following statement:

```
I know a secret_key such that:
  1. commitment(secret_key) ∈ MerkleTree(root)
  2. nullifier_i = H(secret_key || i)
  3. nullifier_i ∉ NullifierSet
  4. withdrawal_amount ≤ remaining_balance(secret_key)
```

The proof’s **public inputs** include:

* Merkle root
* Nullifier
* Withdrawal amount
* Recipient address

The **witness** includes:

* Secret key
* Merkle path
* Internal balance state

This separation ensures that validity is proven without disclosure.

***

### V.2.4 On-Chain Verification and Settlement

The withdrawal contract verifies the proof:

```
function withdraw(
    Proof proof,
    bytes32 root,
    bytes32 nullifier,
    uint256 amount,
    address recipient
) external {
    require(validRoot[root]);
    require(!nullifierUsed[nullifier]);
    require(verifyProof(proof, publicInputs));
    nullifierUsed[nullifier] = true;
    transferV(recipient, amount);
}
```

If verification succeeds:

* Funds are released
* The nullifier is permanently burned
* No state links are introduced

***

### V.2.5 Privacy Properties

From an observer’s perspective:

* The withdrawal could correspond to any commitment in the pool
* Timing does not imply linkage
* Amount does not imply provenance

The recipient learns only that they were paid. They cannot infer the payer’s balance, deposit history, or prior activity.

***

### V.2.6 Failure Modes

Withdrawals fail if:

* The proof is invalid
* The nullifier is reused
* The amount exceeds remaining balance
* The Merkle root is stale or invalid

There are no partial withdrawals or ambiguous outcomes.

***

### V.2.7 Implications

This flow enables Abyss to function as:

* A private payment rail
* A settlement layer for exchanges
* A privacy-preserving payout mechanism

All without accounts, sessions, or persistent identity.

***
