- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
6.2 KiB
Defender Access Control Integration
Date: 2025-12-11 Reference: OpenZeppelin Access Control Documentation
📚 Current Implementation
MainnetTether & TransactionMirror
Both contracts use a simple admin pattern (similar to OpenZeppelin's Ownable):
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
adminaddress controls all administrative functions - Functions are protected with
onlyAdminmodifier - 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:
- Check for
DEFENDER_ADMINenvironment variable first - Fall back to
TETHER_ADMIN/MIRROR_ADMINif Defender not set - Deploy contracts with Defender address as
admin
// 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:
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_ROLEto 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:
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
-
Create Defender Relayer
- Go to OpenZeppelin Defender
- Create a new relayer
- Copy the relayer address
-
Configure Environment
DEFENDER_ADMIN=<defender_relayer_address> -
Deploy Contracts
- Contracts will use Defender address as admin
- All admin functions can be executed via Defender
-
Set Up Defender Actions
- Create Defender actions for
anchorStateProof() - Create Defender actions for
mirrorTransaction() - Configure Defender policies and rate limits
- Create Defender actions for
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:
- Deploy new version with
AccessControl - Grant
DEFAULT_ADMIN_ROLEto Defender - Set up specific roles (e.g.,
ANCHOR_ROLE,PAUSE_ROLE) - Migrate admin functions to use
onlyRolemodifiers
Current → AccessManager (If Needed)
For centralized permission management:
- Deploy
AccessManagercontract - Set Defender as initial admin
- Update contracts to inherit
AccessManaged - 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
AccessControlorAccessManagerlater if needed
📚 References
- OpenZeppelin Access Control Documentation
- OpenZeppelin Defender Documentation
- Ownable Pattern
- AccessControl Pattern
- AccessManager Pattern
Last Updated: 2025-12-11 Status: Current Implementation Aligned with OpenZeppelin Best Practices