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

# Registry System

> Registry architecture for whitelisting, authorization, and configuration management

## Overview

The zkp2p protocol uses a **registry system** to manage whitelists, authorizations, and configuration for various protocol components. Registries decouple authorization logic from core contracts, enabling flexible upgrades and governance.

<Info>
  Registries allow the protocol to add new payment methods, escrows, orchestrators, and hooks without upgrading core contracts.
</Info>

## Registry Architecture

```mermaid theme={null}
graph TD
    A[PaymentVerifierRegistry] -->|Maps methods to verifiers| B[UnifiedPaymentVerifier]
    C[EscrowRegistry] -->|Whitelists escrows| D[Orchestrator]
    E[OrchestratorRegistry] -->|Authorizes orchestrators| F[Escrow]
    G[NullifierRegistry] -->|Prevents double-spend| B
    H[PostIntentHookRegistry] -->|Whitelists hooks| D
    I[RelayerRegistry] -->|Whitelists relayers| D
    
    style A fill:#e1f5ff
    style C fill:#fff4e6
    style E fill:#ffe6e6
    style G fill:#e6ffe6
```

## Core Registries

### 1. PaymentVerifierRegistry

Maps payment methods to their verifiers and supported currencies.

**Location**: `contracts/registries/PaymentVerifierRegistry.sol`

#### Data Structure

```solidity theme={null}
struct PaymentMethodConfig {
    bool initialized;
    address verifier;
    mapping(bytes32 => bool) isCurrency;
    bytes32[] currencies;
}

mapping(bytes32 => PaymentMethodConfig) public store;
bytes32[] public paymentMethods;
```

#### Key Functions

**Add Payment Method**:

```solidity theme={null}
function addPaymentMethod(
    bytes32 _paymentMethod,
    address _verifier,
    bytes32[] calldata _currencies
) external onlyOwner
```

Example usage:

```solidity theme={null}
registry.addPaymentMethod(
    keccak256("venmo"),
    unifiedVerifierAddress,
    [keccak256("USD")]
);
```

**Add Currencies**:

```solidity theme={null}
function addCurrencies(
    bytes32 _paymentMethod, 
    bytes32[] calldata _currencies
) public onlyOwner
```

Example:

```solidity theme={null}
registry.addCurrencies(
    keccak256("wise"),
    [
        keccak256("USD"),
        keccak256("EUR"),
        keccak256("GBP")
    ]
);
```

**Remove Payment Method**:

```solidity theme={null}
function removePaymentMethod(bytes32 _paymentMethod) external onlyOwner
```

Removes the payment method and all associated currencies.

#### Query Functions

```solidity theme={null}
function isPaymentMethod(bytes32 _paymentMethod) external view returns (bool);
function getPaymentMethods() external view returns (bytes32[] memory);
function getVerifier(bytes32 _paymentMethod) external view returns (address);
function isCurrency(bytes32 _paymentMethod, bytes32 _currencyCode) external view returns (bool);
function getCurrencies(bytes32 _paymentMethod) external view returns (bytes32[] memory);
```

#### Usage in Protocol

**Orchestrator** queries the registry during intent validation (from `contracts/Orchestrator.sol:416`):

```solidity theme={null}
address verifier = paymentVerifierRegistry.getVerifier(_intent.paymentMethod);
if (verifier == address(0)) revert PaymentMethodDoesNotExist(_intent.paymentMethod);
```

**Escrow** validates payment methods during deposit creation (from `contracts/Escrow.sol:1060`):

```solidity theme={null}
if (!paymentVerifierRegistry.isPaymentMethod(paymentMethod)) {
    revert PaymentMethodNotWhitelisted(paymentMethod);
}
```

### 2. EscrowRegistry

Whitelists Escrow contracts that can be used with the Orchestrator.

**Location**: `contracts/registries/EscrowRegistry.sol`

#### State Variables

```solidity theme={null}
bool public acceptAllEscrows;
mapping(address => bool) public isWhitelistedEscrow;
address[] public escrows;
```

#### Key Functions

**Add Escrow**:

```solidity theme={null}
function addEscrow(address _escrow) external onlyOwner
```

**Remove Escrow**:

```solidity theme={null}
function removeEscrow(address _escrow) external onlyOwner
```

**Toggle Accept All**:

```solidity theme={null}
function setAcceptAllEscrows(bool _acceptAll) external onlyOwner
```

When `acceptAllEscrows == true`, the Orchestrator accepts intents for any escrow (useful for permissionless deployments).

#### Query Functions

```solidity theme={null}
function isAcceptingAllEscrows() external view returns (bool);
function getWhitelistedEscrows() external view returns (address[] memory);
```

#### Usage in Protocol

**Orchestrator** validates escrow during intent signaling (from `contracts/Orchestrator.sol:411`):

```solidity theme={null}
if (!escrowRegistry.isWhitelistedEscrow(_intent.escrow) && !escrowRegistry.isAcceptingAllEscrows()) {
    revert EscrowNotWhitelisted(_intent.escrow);
}
```

### 3. OrchestratorRegistry

Authorizes Orchestrator contracts that can call Escrow functions.

**Location**: `contracts/registries/OrchestratorRegistry.sol`

#### State Variables

```solidity theme={null}
mapping(address => bool) public override isOrchestrator;
```

#### Key Functions

**Add Orchestrator**:

```solidity theme={null}
function addOrchestrator(address _orchestrator) external override onlyOwner
```

**Remove Orchestrator**:

```solidity theme={null}
function removeOrchestrator(address _orchestrator) external override onlyOwner
```

#### Usage in Protocol

**Escrow** validates orchestrator for liquidity operations (from `contracts/Escrow.sol:103`):

```solidity theme={null}
modifier onlyOrchestrator() {
    if (msg.sender != address(orchestrator)) revert UnauthorizedCaller(msg.sender, address(orchestrator));
    _;
}
```

**Payment Verifiers** authorize orchestrators (from `contracts/unifiedVerifier/BaseUnifiedPaymentVerifier.sol:48`):

```solidity theme={null}
modifier onlyOrchestrator() {
    require(orchestratorRegistry.isOrchestrator(msg.sender), "Only orchestrator can call");
    _;
}
```

<Warning>
  The Escrow contract uses a **direct reference** to its orchestrator, while payment verifiers use the registry. This means Escrow trusts a single orchestrator, while verifiers can work with multiple.
</Warning>

### 4. NullifierRegistry

Prevents double-spending of off-chain payments.

**Location**: `contracts/registries/NullifierRegistry.sol`

#### State Variables

```solidity theme={null}
mapping(bytes32 => bool) public isNullified;
mapping(address => bool) public isWriter;
address[] public writers;
```

#### Access Control

Only addresses with write permissions (payment verifiers) can add nullifiers:

```solidity theme={null}
modifier onlyWriter() {
    require(isWriter[msg.sender], "Only addresses with write permissions can call");
    _;
}
```

#### Key Functions

**Add Nullifier** (Writer Only):

```solidity theme={null}
function addNullifier(bytes32 _nullifier) external onlyWriter {
    require(!isNullified[_nullifier], "Nullifier already exists");
    isNullified[_nullifier] = true;
    emit NullifierAdded(_nullifier, msg.sender);
}
```

**Grant Write Permission** (Owner Only):

```solidity theme={null}
function addWritePermission(address _newWriter) external onlyOwner
```

**Revoke Write Permission** (Owner Only):

```solidity theme={null}
function removeWritePermission(address _removedWriter) external onlyOwner
```

#### Query Functions

```solidity theme={null}
function isNullified(bytes32 _nullifier) external view returns (bool);
function getWriters() external view returns (address[] memory);
```

#### Usage in Protocol

**UnifiedPaymentVerifier** nullifies payments after verification (from `contracts/unifiedVerifier/BaseUnifiedPaymentVerifier.sol:125`):

```solidity theme={null}
function _validateAndAddNullifier(bytes32 _nullifier) internal {
    require(!nullifierRegistry.isNullified(_nullifier), "Nullifier has already been used");
    nullifierRegistry.addNullifier(_nullifier);
}
```

### 5. PostIntentHookRegistry

Whitelists post-intent hooks that can be executed after fulfillment.

**Location**: `contracts/registries/PostIntentHookRegistry.sol` (interface reference)

#### Key Functions

```solidity theme={null}
function addHook(address _hook) external onlyOwner;
function removeHook(address _hook) external onlyOwner;
function isWhitelistedHook(address _hook) external view returns (bool);
```

#### Usage in Protocol

**Orchestrator** validates hooks during intent signaling (from `contracts/Orchestrator.sol:404`):

```solidity theme={null}
if (address(_intent.postIntentHook) != address(0)) {
    if (!postIntentHookRegistry.isWhitelistedHook(address(_intent.postIntentHook))) {
        revert PostIntentHookNotWhitelisted(address(_intent.postIntentHook));
    }
}
```

### 6. RelayerRegistry

Whitelists relayers that can signal multiple intents simultaneously.

**Location**: `contracts/registries/RelayerRegistry.sol` (interface reference)

#### Key Functions

```solidity theme={null}
function addRelayer(address _relayer) external onlyOwner;
function removeRelayer(address _relayer) external onlyOwner;
function isWhitelistedRelayer(address _relayer) external view returns (bool);
```

#### Usage in Protocol

**Orchestrator** checks relayer status for multiple intent permission (from `contracts/Orchestrator.sol:392`):

```solidity theme={null}
bool canHaveMultipleIntents = relayerRegistry.isWhitelistedRelayer(msg.sender) || allowMultipleIntents;
if (!canHaveMultipleIntents && accountIntents[msg.sender].length > 0) {
    revert AccountHasActiveIntent(msg.sender, accountIntents[msg.sender][0]);
}
```

<Info>
  Whitelisted relayers can always have multiple active intents, even if `allowMultipleIntents == false`.
</Info>

## Payment Method Hashing

Payment methods and currencies are identified by their keccak256 hash:

```solidity theme={null}
// Payment method hashes
bytes32 venmoHash = keccak256("venmo");     // 0x8c5e...
bytes32 paypalHash = keccak256("paypal");   // 0x3a7f...
bytes32 wiseHash = keccak256("wise");       // 0x9d2e...

// Currency hashes  
bytes32 usdHash = keccak256("USD");         // 0x783a...
bytes32 eurHash = keccak256("EUR");         // 0x4f3c...
bytes32 gbpHash = keccak256("GBP");         // 0x2e8d...
```

<Tip>
  **Convention**: Payment methods and currencies should be lowercase when hashed for consistency.
</Tip>

## Registry Upgrade Patterns

### Pattern 1: Adding New Payment Method

```solidity theme={null}
// 1. Deploy new verifier (or use existing UnifiedPaymentVerifier)
UnifiedPaymentVerifier newVerifier = new UnifiedPaymentVerifier(...);

// 2. Add payment method to verifier
newVerifier.addPaymentMethod(keccak256("cashapp"));

// 3. Register in PaymentVerifierRegistry
paymentVerifierRegistry.addPaymentMethod(
    keccak256("cashapp"),
    address(newVerifier),
    [keccak256("USD")]
);

// 4. Grant write permission to verifier on NullifierRegistry
nullifierRegistry.addWritePermission(address(newVerifier));
```

### Pattern 2: Migrating to New Orchestrator

```solidity theme={null}
// 1. Deploy new Orchestrator
Orchestrator newOrchestrator = new Orchestrator(...);

// 2. Add to OrchestratorRegistry
orchestratorRegistry.addOrchestrator(address(newOrchestrator));

// 3. Update Escrow reference (governance)
escrow.setOrchestrator(address(newOrchestrator));

// 4. Optionally remove old orchestrator
orchestratorRegistry.removeOrchestrator(address(oldOrchestrator));
```

### Pattern 3: Adding Currencies to Existing Method

```solidity theme={null}
// Add EUR and GBP support to Venmo
paymentVerifierRegistry.addCurrencies(
    keccak256("venmo"),
    [
        keccak256("EUR"),
        keccak256("GBP")
    ]
);
```

## Registry Events

All registries emit events for off-chain indexing:

### PaymentVerifierRegistry

```solidity theme={null}
event PaymentMethodAdded(bytes32 indexed paymentMethod);
event PaymentMethodRemoved(bytes32 indexed paymentMethod);
event CurrencyAdded(bytes32 indexed paymentMethod, bytes32 indexed currencyCode);
event CurrencyRemoved(bytes32 indexed paymentMethod, bytes32 indexed currencyCode);
```

### EscrowRegistry

```solidity theme={null}
event EscrowAdded(address indexed escrow);
event EscrowRemoved(address indexed escrow);
event AcceptAllEscrowsUpdated(bool acceptAll);
```

### OrchestratorRegistry

```solidity theme={null}
event OrchestratorAdded(address indexed orchestrator);
event OrchestratorRemoved(address indexed orchestrator);
```

### NullifierRegistry

```solidity theme={null}
event NullifierAdded(bytes32 nullifier, address indexed writer);
event WriterAdded(address writer);
event WriterRemoved(address writer);
```

## Access Control Summary

| Registry                    | Owner Actions                         | Writer Actions | Public Read                          |
| --------------------------- | ------------------------------------- | -------------- | ------------------------------------ |
| **PaymentVerifierRegistry** | Add/remove methods & currencies       | N/A            | Query methods, verifiers, currencies |
| **EscrowRegistry**          | Add/remove escrows, toggle accept-all | N/A            | Query whitelisted escrows            |
| **OrchestratorRegistry**    | Add/remove orchestrators              | N/A            | Check if address is orchestrator     |
| **NullifierRegistry**       | Add/remove writers                    | Add nullifiers | Check if nullifier used              |
| **PostIntentHookRegistry**  | Add/remove hooks                      | N/A            | Check if hook whitelisted            |
| **RelayerRegistry**         | Add/remove relayers                   | N/A            | Check if relayer whitelisted         |

## Security Considerations

<CardGroup cols={2}>
  <Card title="Owner Centralization" icon="user-shield">
    All registries are owned by governance. Ensure multisig or DAO controls owner keys.
  </Card>

  <Card title="Writer Permissions" icon="key">
    Only grant NullifierRegistry write permissions to trusted payment verifiers.
  </Card>

  <Card title="Registry Hygiene" icon="broom">
    Remove deprecated payment methods and verifiers to avoid confusion.
  </Card>

  <Card title="Accept-All Risk" icon="triangle-exclamation">
    Enabling `acceptAllEscrows` allows untrusted escrows. Use with caution.
  </Card>
</CardGroup>

## Query Patterns

### Check if Payment Method Supported

```solidity theme={null}
bool isSupported = paymentVerifierRegistry.isPaymentMethod(keccak256("venmo"));
if (isSupported) {
    address verifier = paymentVerifierRegistry.getVerifier(keccak256("venmo"));
    bytes32[] memory currencies = paymentVerifierRegistry.getCurrencies(keccak256("venmo"));
}
```

### Check if Currency Supported

```solidity theme={null}
bool supports = paymentVerifierRegistry.isCurrency(
    keccak256("wise"),
    keccak256("EUR")
);
```

### Check if Escrow Whitelisted

```solidity theme={null}
bool isWhitelisted = escrowRegistry.isWhitelistedEscrow(escrowAddress);
bool acceptsAll = escrowRegistry.isAcceptingAllEscrows();
bool canUse = isWhitelisted || acceptsAll;
```

### Check if Payment Nullified

```solidity theme={null}
bytes32 nullifier = keccak256(abi.encodePacked(
    keccak256("venmo"),
    keccak256(venmoTransactionId)
));
bool isUsed = nullifierRegistry.isNullified(nullifier);
```

## Best Practices

1. **Hash Consistency**: Always use lowercase strings for payment method and currency hashes
2. **Idempotent Queries**: Design off-chain systems to tolerate registry changes
3. **Event Monitoring**: Index registry events to maintain off-chain state
4. **Graceful Degradation**: Handle removed payment methods/currencies gracefully in UI
5. **Test Coverage**: Test registry interactions in integration tests, not just unit tests

## Related Contracts

* [Escrow](/concepts/escrow) - Uses PaymentVerifierRegistry and Orchestrator reference
* [Orchestrator](/concepts/orchestrator) - Uses EscrowRegistry, PaymentVerifierRegistry, PostIntentHookRegistry, RelayerRegistry
* [Payment Verification](/concepts/payment-verification) - Uses OrchestratorRegistry and NullifierRegistry
