// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @title MirrorManager * @notice Registry of mirrored token/contract addresses across chains with replay protection and pausability */ contract MirrorManager { address public admin; bool public paused; // mapping: (sourceChain, sourceAddress) => (destChain => destAddress) mapping(uint64 => mapping(address => mapping(uint64 => address))) public mirrors; mapping(bytes32 => bool) public processed; // optional replay protection for off-chain message ids event AdminChanged(address indexed newAdmin); event Paused(); event Unpaused(); event MirrorSet(uint64 indexed srcChain, address indexed src, uint64 indexed dstChain, address dst); event MirrorRemoved(uint64 indexed srcChain, address indexed src, uint64 indexed dstChain); event Processed(bytes32 indexed id); modifier onlyAdmin() { require(msg.sender == admin, "only admin"); _; } modifier whenNotPaused() { require(!paused, "paused"); _; } constructor(address _admin) { require(_admin != address(0), "zero admin"); admin = _admin; } function setAdmin(address newAdmin) external onlyAdmin { require(newAdmin != address(0), "zero admin"); admin = newAdmin; emit AdminChanged(newAdmin); } function pause() external onlyAdmin { paused = true; emit Paused(); } function unpause() external onlyAdmin { paused = false; emit Unpaused(); } function setMirror(uint64 srcChain, address src, uint64 dstChain, address dst) external onlyAdmin whenNotPaused { require(src != address(0) && dst != address(0), "zero addr"); mirrors[srcChain][src][dstChain] = dst; emit MirrorSet(srcChain, src, dstChain, dst); } function removeMirror(uint64 srcChain, address src, uint64 dstChain) external onlyAdmin whenNotPaused { delete mirrors[srcChain][src][dstChain]; emit MirrorRemoved(srcChain, src, dstChain); } function getMirror(uint64 srcChain, address src, uint64 dstChain) external view returns (address) { return mirrors[srcChain][src][dstChain]; } function markProcessed(bytes32 id) external onlyAdmin { processed[id] = true; emit Processed(id); } }