# Manager Contract

The `Manager.sol` contract serves as the central coordination layer for the entire Worldbook ecosystem. It implements sophisticated access control, fee management, orderbook registration, and emergency response capabilities.

## Contract Overview

* **File**: `Manager.sol`
* **Size**: \~900 lines of code
* **Role**: Central coordination and control layer
* **Security**: Role-based access control with inheritance hierarchy

## Key Responsibilities

### 1. Access Control System

* **Role Management**: Hierarchical role system with inheritance
* **Permission Delegation**: Centralized permission checking for all OrderBooks
* **Emergency Controls**: Pause/unpause capabilities across the entire system

### 2. OrderBook Registry

* **Registration**: Validates and registers new OrderBook contracts
* **Bytecode Verification**: Ensures only legitimate contracts are registered
* **Pair Management**: Manages unique trading pairs and prevents duplicates

### 3. Fee Management

* **4-Tier Fee System**: Sophisticated fee structure with customization options
* **Maker Rebates**: Support for negative maker fees (rebates)
* **Fee Collection**: Centralized fee collection and distribution
* **User Discounts**: Percentage and absolute discount mechanisms

### 4. Token Whitelist and Standard Token Registry

* **Quote Token Control**: Manages which tokens can be used as quote assets
* **Minimum Amounts**: Sets minimum order sizes per token
* **Standard Tokens**: Registry for exact-transfer ERC-20s and optional enforcement for BASE on registration
* **Dynamic Management**: Add/remove tokens from whitelist

### 5. Self-Trade Prevention (STP)

* **User STP Modes**: Configurable self-trade prevention behavior
* **Three Modes**: NONE, EXPIRE\_MAKER, and SKIP
* **Default Mode**: EXPIRE\_MAKER for new users

## Access Control Architecture

### Role Hierarchy

```solidity
DEFAULT_ADMIN_ROLE (Role Management Only)
    │
    ▼
ADMIN_ROLE (Full Operational Control + PAUSER privileges)
    │
    ▼
PAUSER_ROLE (Emergency Response)
```

**Important:** ADMIN\_ROLE automatically has PAUSER\_ROLE privileges through the `hasOrderBookRole` function implementation. The `Manager` contract itself also holds `PAUSER_ROLE` to perform batch pause/unpause.

### Role Definitions

```solidity
// Role constants
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant FACTORY_ROLE = keccak256("FACTORY_ROLE");

// Role checking function used by all OrderBooks with inheritance
function hasOrderBookRole(bytes32 role, address account) external view returns (bool) {
    // Direct role check
    if (hasRole(role, account)) {
        return true;
    }
    
    // Implement role inheritance: ADMIN_ROLE includes PAUSER_ROLE privileges
    if (role == PAUSER_ROLE && hasRole(ADMIN_ROLE, account)) {
        return true;
    }
    
    return false;
}
```

### Role Capabilities

**DEFAULT\_ADMIN\_ROLE:**

* Grant and revoke ADMIN\_ROLE
* Grant and revoke PAUSER\_ROLE
* Role management only (no operational privileges)

**ADMIN\_ROLE:**

* All operational functions
* Fee management
* OrderBook registration control
* Token whitelist management
* System configuration
* Inherits PAUSER\_ROLE privileges

**PAUSER\_ROLE:**

* Emergency pause/unpause operations
* Community managers and emergency responders
* Limited to emergency response only

## Fee Management System

### 4-Tier Fee Structure

Worldbook implements a sophisticated fee system with four layers:

#### Layer 1: Default Fees

```solidity
int256 public override makerFee;    // Can be negative for rebates
uint256 public override takerFee;   // Always non-negative
```

**Maker Rebates:**

* Maker fees can be negative to incentivize liquidity provision
* Rebates are funded from taker fees
* Maximum rebate: 0.05% (500 basis points, different from max fee of 0.5%)

#### Layer 2: OrderBook-Specific Overrides

```solidity
mapping(address => int256) public orderbookMakerFeeOverrides;
mapping(address => uint256) public orderbookTakerFeeOverrides;
```

#### Layer 3: User Percentage Discounts

```solidity
mapping(address => uint256) public userMakerFeeDiscountFactor;
mapping(address => uint256) public userTakerFeeDiscountFactor;
```

#### Layer 4: User Absolute Discounts

```solidity
mapping(address => uint256) public userMakerFeeDiscountAbs;
mapping(address => uint256) public userTakerFeeDiscountAbs;
```

### Fee Calculation Logic

```solidity
// Fee calculation with rebate support
function _calculateMakerFeeRate(address orderbook, address user) internal view returns (int256) {
    // Step 1: Get base rate (orderbook override OR default)
    int256 baseRate = orderbookMakerFeeOverrides[orderbook] != 0 ? 
                      orderbookMakerFeeOverrides[orderbook] : 
                      makerFee;

    // Step 2: Apply percentage discount ONLY if base rate is positive
    int256 afterPercentageDiscount = baseRate;
    if (baseRate > 0) {
        uint256 discountFactor = userMakerFeeDiscountFactor[user];
        if (discountFactor > 0 && discountFactor < 10000000) {
            afterPercentageDiscount = int256(uint256(baseRate) * discountFactor / FEE_DENOM);
        }
    }

    // Step 3: Apply absolute discount (can turn positive fees into rebates)
    uint256 absoluteDiscount = userMakerFeeDiscountAbs[user];
    return afterPercentageDiscount - int256(absoluteDiscount);
}
```

### Fee Collection

```solidity
address public override feeCollector;

function setFeeCollector(address _feeCollector) external override onlyAdminRole {
    if (_feeCollector == address(0)) revert Manager__InvalidFeeCollector();
    if (_feeCollector != feeCollector) {
        address oldFeeCollector = feeCollector;
        feeCollector = _feeCollector;
        emit FeeCollectorUpdated(oldFeeCollector, _feeCollector);
    }
}
```

## OrderBook Registration System

### Registration Process

```solidity
function registerOrderBook(
    address baseToken,
    address quoteToken,
    address orderBookAddress
) external payable virtual override
```

**Validation Steps:**

1. **Access Control**: If `allowAnyoneRegisterOrderBook` is false, only ADMIN\_ROLE may register. Callers with `FACTORY_ROLE` bypass bytecode checks.
2. **Registration Fee**: Require payment of `registrationFee` (admins exempt)
3. **Input Validation**: Verify token addresses and uniqueness
4. **Quote Token Check**: Ensure quote token is whitelisted (if active)
5. **Bytecode Verification**: Verify contract matches expected bytecode (exact or normalized hash)
6. **Parameter Verification**: Validate OrderBook configuration
7. **Storage**: Store registration and emit event
8. **Fee Transfer**: Send fee to collector, refund excess

### Registration Fee System

The Manager supports optional registration fees for OrderBook creation:

```solidity
uint256 public registrationFee = 0.001 ether; // Default: 0.001 ETH

function setRegistrationFee(uint256 _fee) external onlyAdminRole
```

**Key Features:**

* Admin role is exempt from registration fees
* Fees are sent directly to the fee collector
* Excess payment is automatically refunded
* Can be set to 0 to disable fees
* Prevents spam OrderBook creation

### Bytecode Verification

```solidity
bytes32 public override expectedBytecodeHash;

function setExpectedBytecodeHash(bytes32 _newHash) external override onlyAdminRole {
    if (_newHash == bytes32(0)) revert Manager__ZeroBytecodeHash();
    if (_newHash != expectedBytecodeHash) {
        bytes32 oldHash = expectedBytecodeHash;
        expectedBytecodeHash = _newHash;
        emit ExpectedBytecodeHashSet(oldHash, _newHash);
    }
}
```

**Security Benefits:**

* Prevents registration of malicious contracts
* Ensures only approved OrderBook versions are used
* Maintains system integrity and user trust

#### Normalized Bytecode Verification

To support OrderBooks with different immutable constructor parameters (manager/base/quote addresses, decimals, scales), the Manager can verify a canonical normalized runtime hash:

```solidity
bytes32 public override expectedNormalizedBytecodeHash;

function setExpectedNormalizedBytecodeHash(bytes32 _newHash) external onlyAdminRole {
    if (_newHash == bytes32(0)) revert Manager__ZeroBytecodeHash();
    if (_newHash != expectedNormalizedBytecodeHash) {
        bytes32 oldHash = expectedNormalizedBytecodeHash;
        expectedNormalizedBytecodeHash = _newHash;
        emit ExpectedNormalizedBytecodeHashSet(oldHash, _newHash);
    }
}

// Optional fast-path: zero-out configured [offset,length] windows before hashing
function setNormalizationMask(uint32[] calldata offsets, uint32[] calldata lengths) external onlyAdminRole;

// Tooling helper
function computeNormalizedRuntimeHash(address orderBook) external view returns (bytes32);
```

If the caller has `FACTORY_ROLE`, bytecode checks are skipped to allow trusted factories to register books.

#### Normalized Bytecode Verification

To support OrderBooks with different immutable constructor parameters (manager/base/quote addresses, decimals, scales), the Manager can verify a canonical normalized runtime hash:

```solidity
bytes32 public override expectedNormalizedBytecodeHash;

function setExpectedNormalizedBytecodeHash(bytes32 _newHash) external onlyAdminRole {
    if (_newHash == bytes32(0)) revert Manager__ZeroBytecodeHash();
    if (_newHash != expectedNormalizedBytecodeHash) {
        bytes32 oldHash = expectedNormalizedBytecodeHash;
        expectedNormalizedBytecodeHash = _newHash;
        emit ExpectedNormalizedBytecodeHashSet(oldHash, _newHash);
    }
}

// Optional fast-path: zero-out configured [offset,length] windows before hashing
function setNormalizationMask(uint32[] calldata offsets, uint32[] calldata lengths) external onlyAdminRole;

// Tooling helper
function computeNormalizedRuntimeHash(address orderBook) external view returns (bytes32);
```

If the caller has `FACTORY_ROLE`, bytecode checks are skipped to allow trusted factories to register books.

### Pair Management

```solidity
mapping(bytes32 => address) public override orderBooks;
address[] public allOrderBooks;

function getPairHash(address baseToken, address quoteToken) public pure returns (bytes32) {
    // Deterministic hash regardless of token order
    (address token0, address token1) = baseToken < quoteToken ? 
        (baseToken, quoteToken) : (quoteToken, baseToken);
    return keccak256(abi.encodePacked(token0, token1));
}

// Append-only per-pair index (latest registered remains the canonical pointer above)
function getPairOrderBooks(address tokenA, address tokenB) external view returns (address[] memory);
 
// Append-only per-pair index (latest registered remains the canonical pointer above)
function getPairOrderBooks(address tokenA, address tokenB) external view returns (address[] memory);
```

## Quote Token Whitelist System

### Whitelist Control

```solidity
bool public override isQuoteWhitelistActive;
mapping(address => bool) public override isQuoteTokenWhitelisted;
mapping(address => uint256) public override quoteTokenMinAmounts;
```

### Whitelist Management

```solidity
function addOrUpdateQuoteToken(address _token, uint256 _minQuoteAmount) external override onlyAdminRole {
    if (_token == address(0)) revert Manager__ZeroAddressToken();

    bool wasWhitelisted = isQuoteTokenWhitelisted[_token];
    uint256 oldMinAmount = quoteTokenMinAmounts[_token];

    if (!wasWhitelisted || oldMinAmount != _minQuoteAmount) {
        isQuoteTokenWhitelisted[_token] = true;
        quoteTokenMinAmounts[_token] = _minQuoteAmount;
        
        if (!wasWhitelisted) {
            allWhitelistedQuoteTokens.push(_token);
            quoteTokenToIndex[_token] = allWhitelistedQuoteTokens.length - 1;
            emit QuoteTokenWhitelisted(_token, _minQuoteAmount);
        } else {
            emit QuoteTokenMinAmountUpdated(_token, oldMinAmount, _minQuoteAmount);
        }
    }
}
```

## Emergency Controls

### System-Wide Pause

```solidity
function pauseAllOrderBooks() external onlyPauserRole returns (uint256[] memory pausedIndices) {
    uint256 length = allOrderBooks.length;
    uint256[] memory tempIndices = new uint256[](length);
    uint256 pausedCount = 0;
    
    for (uint256 i = 0; i < length; i++) {
        try IOrderBook(allOrderBooks[i]).pause() {
            tempIndices[pausedCount] = i;
            pausedCount++;
        } catch {
            // Continue even if individual pause fails
        }
    }
    
    // Return successfully paused indices
    pausedIndices = new uint256[](pausedCount);
    for (uint256 i = 0; i < pausedCount; i++) {
        pausedIndices[i] = tempIndices[i];
    }
    
    emit AllOrderBooksPaused(msg.sender, pausedIndices);
    return pausedIndices;
}
```

### System-Wide Unpause

```solidity
function unpauseAllOrderBooks() external onlyPauserRole returns (uint256[] memory unpausedIndices) {
    // Similar implementation for unpausing all OrderBooks
}
```

### Batch Pause/Unpause Operations

For more granular control and gas efficiency when dealing with many OrderBooks:

```solidity
function pauseOrderBooksBatch(uint256 startIndex, uint256 count) 
    external 
    onlyPauserRole 
    returns (address[] memory pausedAddresses)

function unpauseOrderBooksBatch(uint256 startIndex, uint256 count) 
    external 
    onlyPauserRole 
    returns (address[] memory unpausedAddresses)
```

**Batch Operation Benefits:**

* Avoids gas limits when pausing/unpausing many OrderBooks
* Provides pagination for large-scale operations
* Returns specific addresses that were successfully affected
* Enables targeted emergency responses
* Continues operation even if individual OrderBooks fail to pause/unpause

**Usage Example:**

```solidity
// Pause OrderBooks 0-99
pauseOrderBooksBatch(0, 100);

// Pause OrderBooks 100-199
pauseOrderBooksBatch(100, 100);

// Returns array of successfully paused addresses
```

### Pauser Management

Admins can manage who has emergency pause privileges:

```solidity
function addPauser(address account) external {
    // Only ADMIN_ROLE can add pausers
    if (!this.hasOrderBookRole(ADMIN_ROLE, msg.sender)) {
        revert AccessControlUnauthorizedAccount(msg.sender, ADMIN_ROLE);
    }
    _grantRole(PAUSER_ROLE, account);
}

function removePauser(address account) external {
    // Only ADMIN_ROLE can remove pausers
    if (!this.hasOrderBookRole(ADMIN_ROLE, msg.sender)) {
        revert AccessControlUnauthorizedAccount(msg.sender, ADMIN_ROLE);
    }
    _revokeRole(PAUSER_ROLE, account);
}
```

**Emergency Use Cases:**

* Critical security vulnerabilities discovered
* Market manipulation attempts
* Extreme market conditions
* Regulatory compliance requirements

## Configuration Functions

### Fee Configuration

```solidity
function setFees(int256 _makerFee, uint256 _takerFee) external override onlyAdminRole {
    // Validate taker fee
    if (_takerFee > MAX_FEE) revert Manager__FeeTooHigh();
    
    // Validate maker fee (different limits for fees vs rebates)
    if (_makerFee < 0) {
        // For rebates: limit to MAX_REBATE (0.05%)
        if (uint256(-_makerFee) > MAX_REBATE) revert Manager__FeeTooHigh();
    } else {
        // For positive fees: limit to MAX_FEE (0.5%)
        if (uint256(_makerFee) > MAX_FEE) revert Manager__FeeTooHigh();
    }
    
    if (makerFee != _makerFee || takerFee != _takerFee) {
        int256 oldMakerFee = makerFee;
        uint256 oldTakerFee = takerFee;
        makerFee = _makerFee;
        takerFee = _takerFee;
        emit FeesUpdated(oldMakerFee, _makerFee, oldTakerFee, _takerFee);
    }
}
```

### Registration Control

```solidity
function setAllowAnyoneRegisterOrderBook(bool _allowed) external override onlyAdminRole {
    if (_allowed != allowAnyoneRegisterOrderBook) {
        allowAnyoneRegisterOrderBook = _allowed;
        emit AllowAnyoneRegisterOrderBookSet(_allowed);
    }
}
```

## Events

### Registration Events

```solidity
event OrderBookRegistered(
    bytes32 indexed pairHash,
    address indexed baseToken,
    address indexed quoteToken,
    address orderBookAddress
);

event ExpectedBytecodeHashSet(bytes32 oldHash, bytes32 newHash);
event ExpectedNormalizedBytecodeHashSet(bytes32 oldHash, bytes32 newHash);
event AllowAnyoneRegisterOrderBookSet(bool allowed);
```

### Fee Events

```solidity
event FeesUpdated(
    int256 oldMakerFee,
    int256 newMakerFee,
    uint256 oldTakerFee,
    uint256 newTakerFee
);

event FeeCollectorUpdated(
    address indexed oldCollector,
    address indexed newCollector
);
```

### Emergency Events

```solidity
event AllOrderBooksPaused(
    address indexed pauser,
    uint256[] pausedIndices
);

event AllOrderBooksUnpaused(
    address indexed unpauser,
    uint256[] unpausedIndices
);

event OrderBooksPausedBatch(
    address indexed pauser,
    uint256 startIndex,
    uint256 endIndex,
    address[] pausedAddresses
);

event OrderBooksUnpausedBatch(
    address indexed unpauser,
    uint256 startIndex,
    uint256 endIndex,
    address[] unpausedAddresses
);
```

## Security Features

### Input Validation

* Zero address checks for all critical parameters
* Fee rate bounds checking (MAX\_FEE = 0.5%, MAX\_REBATE = 0.05%)
* Bytecode hash validation
* Token pair uniqueness enforcement

### Access Control

* Role-based permissions with inheritance
* Centralized role checking for all OrderBooks
* Emergency response capabilities

### Emergency Response

* System-wide pause/unpause functionality
* Graceful error handling (continues if individual OrderBook fails)
* Event emission for transparency

## Standard Token Registry and Token Denylist

### Standard ERC-20 Registry

```solidity
function setStandardToken(address token, bool isStandard) external onlyAdminRole;
function isStandardToken(address token) external view returns (bool);
function setEnforceStandardBaseOnRegister(bool enforce) external onlyAdminRole;
```

* When enforcement is enabled, `registerOrderBook` requires the BASE token to be marked standard.
* “Standard” means exact-transfer, non-rebasing ERC-20 for gas-fast paths.

### Emergency Token Denylist

```solidity
function setTokenDenied(address token, bool denied) external onlyAdminRole;
function isTokenDenied(address token) external view returns (bool);
```

Denied tokens cannot be used in new OrderBooks (applies to both base and quote), regardless of whitelist status.

## Self-Trade Prevention (STP)

### STP Modes

The Manager contract supports three STP modes for preventing self-trading:

```solidity
enum STPMode {
    NONE,          // No self-trade prevention
    EXPIRE_MAKER,  // Cancel maker order when self-trade detected (default)
    SKIP           // Skip maker order without matching
}
```

### STP Configuration

```solidity
// Set user's STP mode
function setUserSTPMode(STPMode mode) external override {
    userSTPMode[msg.sender] = mode;
    _isStpModeExplicitlySet[msg.sender] = true;
}

// Get user's STP mode (defaults to EXPIRE_MAKER)
function getUserSTPMode(address user) external view override returns (STPMode) {
    if (!_isStpModeExplicitlySet[user]) {
        return STPMode.EXPIRE_MAKER;
    }
    return userSTPMode[user];
}
```

### STP Behavior

**NONE**: Self-trades are allowed and executed normally

**EXPIRE\_MAKER**: When self-trade is detected:

* Maker order is automatically cancelled
* Collateral is refunded to the maker
* Taker order continues to match with other orders

**SKIP**: When self-trade is detected:

* Maker order is skipped (remains active)
* Taker order continues to match with other orders

## Integration Points

### OrderBook Integration

```solidity
// OrderBooks call this for role checking
function hasOrderBookRole(bytes32 role, address account) external view returns (bool);

// OrderBooks call this for fee calculation
function getMakerFeeRate(address orderbook, address user) external view returns (int256);
function getTakerFeeRate(address orderbook, address user) external view returns (uint256);

// OrderBooks call this for STP mode checking
function getUserSTPMode(address user) external view returns (STPMode);
```

### Frontend Integration

* Event monitoring for system changes
* Role-based UI elements
* Real-time fee calculation
* Emergency status indicators

The Manager contract provides the foundational infrastructure for secure, scalable, and maintainable decentralized exchange operations while maintaining flexibility for future enhancements and community governance.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://world-book.gitbook.io/worldbook/technical-documentation/manager-contract.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
