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
Quote Token Control: Manages which tokens can be used as quote assets
Minimum Amounts: Sets minimum order sizes per token
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
DEFAULT_ADMIN_ROLE (Role Management Only)
│
â–¼
ADMIN_ROLE (Full Operational Control)
│
â–¼
PAUSER_ROLE (Emergency Response)
Role Definitions
// Role constants
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
// Role checking function used by all OrderBooks
function hasOrderBookRole(bytes32 role, address account) external view returns (bool) {
return hasRole(role, account);
}
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
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
Rebates cannot exceed the corresponding taker fee amount
Layer 2: OrderBook-Specific Overrides
mapping(address => int256) public orderbookMakerFeeOverrides;
mapping(address => uint256) public orderbookTakerFeeOverrides;
Layer 3: User Percentage Discounts
mapping(address => uint256) public userMakerFeeDiscountFactor;
mapping(address => uint256) public userTakerFeeDiscountFactor;
Layer 4: User Absolute Discounts
mapping(address => uint256) public userMakerFeeDiscountAbs;
mapping(address => uint256) public userTakerFeeDiscountAbs;
Fee Calculation Logic
// 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
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
function registerOrderBook(
address baseToken,
address quoteToken,
address orderBookAddress
) external virtual override
Validation Steps:
Access Control: Check if caller has permission
Input Validation: Verify token addresses and uniqueness
Quote Token Check: Ensure quote token is whitelisted (if active)
Bytecode Verification: Verify contract matches expected bytecode
Parameter Verification: Validate OrderBook configuration
Storage: Store registration and emit event
Bytecode Verification
bytes32 public override expectedBytecodeHash;
function setExpectedBytecodeHash(bytes32 _newHash) external override onlyAdminRole {
if (_newHash == bytes32(0)) revert Manager__ZeroBytecodeHash();
if (_newHash != expectedBytecodeHash) {
expectedBytecodeHash = _newHash;
emit ExpectedBytecodeHashSet(_newHash);
}
}
Security Benefits:
Prevents registration of malicious contracts
Ensures only approved OrderBook versions are used
Maintains system integrity and user trust
Pair Management
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));
}
Quote Token Whitelist System
Whitelist Control
bool public override isQuoteWhitelistActive;
mapping(address => bool) public override isQuoteTokenWhitelisted;
mapping(address => uint256) public override quoteTokenMinAmounts;
Whitelist Management
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
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
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:
function pauseOrderBooksBatch(uint256 startIndex, uint256 count)
external
onlyPauserRole
returns (address[] memory pausedAddresses) {
uint256 length = allOrderBooks.length;
if (startIndex >= length) {
return new address[](0);
}
uint256 endIndex = startIndex + count;
if (endIndex > length) {
endIndex = length;
}
// Pause OrderBooks in the specified range
// Returns addresses of successfully paused OrderBooks
}
function unpauseOrderBooksBatch(uint256 startIndex, uint256 count)
external
onlyPauserRole
returns (address[] memory unpausedAddresses) {
// Similar implementation for batch unpausing
}
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
Pauser Management
Admins can manage who has emergency pause privileges:
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
function setFees(int256 _makerFee, uint256 _takerFee) external override onlyAdminRole {
// Validate taker fee
if (_takerFee > MAX_FEE) revert Manager__FeeTooHigh();
// Validate maker fee (can be negative for rebates)
if (_makerFee < 0) {
if (uint256(-_makerFee) > MAX_FEE) revert Manager__FeeTooHigh();
} else {
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
function setAllowAnyoneRegisterOrderBook(bool _allowed) external override onlyAdminRole {
if (_allowed != allowAnyoneRegisterOrderBook) {
allowAnyoneRegisterOrderBook = _allowed;
emit AllowAnyoneRegisterOrderBookSet(_allowed);
}
}
Events
Registration Events
event OrderBookRegistered(
bytes32 indexed pairHash,
address indexed baseToken,
address indexed quoteToken,
address orderBookAddress
);
event ExpectedBytecodeHashSet(bytes32 indexed newHash);
event AllowAnyoneRegisterOrderBookSet(bool allowed);
Fee Events
event FeesUpdated(
int256 oldMakerFee,
int256 newMakerFee,
uint256 oldTakerFee,
uint256 newTakerFee
);
event FeeCollectorUpdated(
address indexed oldCollector,
address indexed newCollector
);
Emergency Events
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%)
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
Self-Trade Prevention (STP)
STP Modes
The Manager contract supports three STP modes for preventing self-trading:
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
// 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
// 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.
Last updated