# Defender Access Control Integration **Date**: 2025-12-11 **Reference**: [OpenZeppelin Access Control Documentation](https://docs.openzeppelin.com/contracts/5.x/access-control#access-management) --- ## 📚 Current Implementation ### MainnetTether & TransactionMirror Both contracts use a **simple admin pattern** (similar to OpenZeppelin's `Ownable`): ```solidity address public admin; bool public paused; modifier onlyAdmin() { require(msg.sender == admin, "only admin"); _; } ``` This is equivalent to OpenZeppelin's `Ownable` pattern, where: - A single `admin` address controls all administrative functions - Functions are protected with `onlyAdmin` modifier - Admin can be changed via `setAdmin()` function --- ## 🔐 Defender Integration ### Using Defender as Admin According to OpenZeppelin's documentation, **"a contract can also be the owner of another one"**. This means: ✅ **Defender Relayer Address** can be set as the `admin` of our contracts This provides: - Automated transaction execution - Gas price optimization - Transaction monitoring and alerts - Multi-signature support (via Defender) - Rate limiting and security policies - Non-custodial key management ### Current Setup Our deployment scripts are configured to: 1. Check for `DEFENDER_ADMIN` environment variable first 2. Fall back to `TETHER_ADMIN`/`MIRROR_ADMIN` if Defender not set 3. Deploy contracts with Defender address as `admin` ```solidity // Deployment script pattern address admin = vm.envOr("DEFENDER_ADMIN", vm.envOr("TETHER_ADMIN", address(0))); MainnetTether tether = new MainnetTether(admin); ``` --- ## 🚀 Advanced Access Control Options ### Option 1: Current Simple Admin (Recommended for Now) **Status**: ✅ **Currently Implemented** - Simple and effective - Single Defender address as admin - All admin functions controlled by Defender - Easy to understand and audit **Use Case**: Perfect for contracts with a single administrative role ### Option 2: AccessControl (Role-Based) If you need more granular permissions in the future, you could upgrade to OpenZeppelin's `AccessControl`: ```solidity import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; contract MainnetTether is AccessControl { bytes32 public constant ANCHOR_ROLE = keccak256("ANCHOR_ROLE"); bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE"); constructor(address defenderAdmin) { _grantRole(DEFAULT_ADMIN_ROLE, defenderAdmin); } function anchorStateProof(...) external onlyRole(ANCHOR_ROLE) { // Only accounts with ANCHOR_ROLE can call this } function pause() external onlyRole(PAUSE_ROLE) { // Only accounts with PAUSE_ROLE can call this } } ``` **Benefits**: - Multiple roles (e.g., `ANCHOR_ROLE`, `PAUSE_ROLE`) - Different permissions for different functions - Defender can be `DEFAULT_ADMIN_ROLE` to manage all roles **When to Use**: If you need different accounts for different functions ### Option 3: AccessManager (Centralized Permission Management) For complex protocols with multiple contracts, OpenZeppelin's `AccessManager` provides centralized permission management: ```solidity import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; contract MainnetTether is AccessManaged { constructor(address accessManager) AccessManaged(accessManager) {} function anchorStateProof(...) public restricted { // Access controlled by AccessManager } } ``` **Benefits**: - Centralized permission management across all contracts - Execution delays for security - Role-based access with delays - Defender can be the initial admin **When to Use**: For complex multi-contract systems --- ## 📋 Defender Configuration ### Setting Up Defender 1. **Create Defender Relayer** - Go to [OpenZeppelin Defender](https://defender.openzeppelin.com/) - Create a new relayer - Copy the relayer address 2. **Configure Environment** ```bash DEFENDER_ADMIN= ``` 3. **Deploy Contracts** - Contracts will use Defender address as admin - All admin functions can be executed via Defender 4. **Set Up Defender Actions** - Create Defender actions for `anchorStateProof()` - Create Defender actions for `mirrorTransaction()` - Configure Defender policies and rate limits ### Defender Benefits According to OpenZeppelin's best practices: - ✅ **Automated Execution**: Defender can execute transactions automatically - ✅ **Gas Optimization**: Defender optimizes gas prices - ✅ **Monitoring**: Real-time alerts for contract events - ✅ **Security**: Multi-signature support and rate limiting - ✅ **Non-Custodial**: Keys managed securely by Defender --- ## 🔄 Migration Path ### Current → AccessControl (If Needed) If you need role-based access control later: 1. Deploy new version with `AccessControl` 2. Grant `DEFAULT_ADMIN_ROLE` to Defender 3. Set up specific roles (e.g., `ANCHOR_ROLE`, `PAUSE_ROLE`) 4. Migrate admin functions to use `onlyRole` modifiers ### Current → AccessManager (If Needed) For centralized permission management: 1. Deploy `AccessManager` contract 2. Set Defender as initial admin 3. Update contracts to inherit `AccessManaged` 4. Configure roles and permissions in AccessManager --- ## ✅ Recommendation **For MainnetTether and TransactionMirror**: ✅ **Keep the current simple admin pattern** with Defender as admin **Reasons**: - Simple and effective for single-admin contracts - Defender provides all necessary security features - Easy to understand and audit - No need for complex role-based access control - Can upgrade to `AccessControl` or `AccessManager` later if needed --- ## 📚 References - [OpenZeppelin Access Control Documentation](https://docs.openzeppelin.com/contracts/5.x/access-control#access-management) - [OpenZeppelin Defender Documentation](https://docs.openzeppelin.com/defender) - [Ownable Pattern](https://docs.openzeppelin.com/contracts/5.x/access-control#ownership-and-ownable) - [AccessControl Pattern](https://docs.openzeppelin.com/contracts/5.x/access-control#role-based-access-control) - [AccessManager Pattern](https://docs.openzeppelin.com/contracts/5.x/access-control#access-management) --- **Last Updated**: 2025-12-11 **Status**: Current Implementation Aligned with OpenZeppelin Best Practices