// SPDX-License-Identifier: MIT // PermissionedManager contract that controls minting based on available minting credits // and allows contract updates with a delay after an update proposal. pragma solidity ^0.8.20; import {IPermissionedMintingManager} from "../interfaces/IPermissionedMintingManager.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; /** * @title PermissionedManager * @notice This contract controls minting permissions based on minting credits and handles contract upgrades * with a proposal system that includes a delay before an upgrade is permitted. */ contract JiritsuERC20PermissionedMintingManagerPassThrough is IPermissionedMintingManager, AccessControl { uint256 public updateProposalTimestamp; // Timestamp when an update was proposed address public pendingAddress; // Proposed new permissioned manager address address public finalAddress; // new permissioned manager address // slither-disable-next-line naming-convention uint256 public immutable WAITING_PERIOD; // Waiting period for contract updates address public managedContract; /* The contract managed by this PermissionedManager. This value is important for security so that only the managed contract can communicate with this manager contract. */ // Role definitions bytes32 public constant SET_MANAGED_CONTRACT_ROLE = keccak256("SET_MANAGED_CONTRACT_ROLE"); // Events /** * @dev Emitted when the countdown for setting a new permissioned minting manager begins. * @param newContractAddress The address of the new permissioned minting manager contract. */ event UpgradeReviewPeriodStart(address indexed newContractAddress); /** * @dev Emitted when a new contract is set to be managed by this PermissionedManager. * @param contractAddress The address of the contract now being managed. */ event NewManagedContract(address indexed contractAddress); /** * @dev Emitted when a checkMintingPermission call is made. */ event MintingAllowedByDefault(); // Custom Errors error NoZeroAddress(); // Thrown when a zero address is provided error OnlySetOnce(); // Thrown when attempting to set managedContract more than once error OnlyManagedContract(); // Thrown when a function restricted to the managed contract is called by another address error NotSupported(); // Thrown when an unsupported feature is called error OnlyNewManagerContract(); // Thrown when migrateStateToContract is called by a non-finalized address // Modifiers modifier onlyManagedContract() { if (msg.sender != managedContract) { revert OnlyManagedContract(); } _; } /** * @dev Constructor that sets the deployer as both the admin and a credit reporter. * @param waitingPeriod The delay period (in seconds) before an update can be finalized. */ constructor(uint256 waitingPeriod) { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); // Set deployer as the admin _grantRole(SET_MANAGED_CONTRACT_ROLE, msg.sender); // Set deployer as the contract setter WAITING_PERIOD = waitingPeriod; // Set the custom waiting period } /** * @notice Sets the contract to be managed by this PermissionedManager. * @dev Can only be set once. Reverts if `contractAddress` is the zero address or if it has already been set. * @param contractAddress The address of the contract to be managed. */ function setManagedContract( address contractAddress ) external onlyRole(SET_MANAGED_CONTRACT_ROLE) { if (managedContract != address(0)) revert OnlySetOnce(); if (contractAddress == address(0)) revert NoZeroAddress(); managedContract = contractAddress; emit NewManagedContract(contractAddress); } /** * @notice Allows all transfers by default. */ /* solhint-disable no-empty-blocks */ function checkTransferPermission( address /*from*/, address /*to*/, uint256 /*amount*/ ) external onlyManagedContract { // This is a stub implementation and does not perform any checks. } /** * @notice Always allows minting. */ function checkMintingPermission( address /*account*/, uint256 /*amount*/, address /*sender*/ ) external onlyManagedContract { emit MintingAllowedByDefault(); } /** * @notice Initiates a cross-chain token transfer (stub implementation). */ function transferToChain( uint16 /*chainId*/, address /*account*/, uint256 /*amount*/ ) external pure { revert NotSupported(); } /** * @notice Handles token redemption (stub implementation). * @param account The account whose tokens are being redeemed. * @param amount The amount of tokens to redeem. */ // solhint-disable-next-line no-empty-blocks function triggerRedemption(address account, uint256 amount) external { // No redemption bridge messaging in this version. } /** * @notice Checks if the contract upgrade is allowed. * @dev The upgrade is allowed only after the proposal has been made and a certain time has passed. * Reverts if the caller is not the managed contract. * @param newContractAddress The address of the proposed new contract. * @return bool True if the upgrade is allowed, false otherwise. */ function isUpdateAllowed( address newContractAddress, address /*sender*/ ) external onlyManagedContract returns (bool) { if (newContractAddress == address(0)) revert NoZeroAddress(); if (newContractAddress != pendingAddress) { pendingAddress = newContractAddress; updateProposalTimestamp = block.timestamp; emit UpgradeReviewPeriodStart(newContractAddress); return false; } // Use the custom waiting period for the delay // slither-disable-next-line timestamp if (block.timestamp >= updateProposalTimestamp + WAITING_PERIOD) { finalAddress = pendingAddress; return true; } return false; } /** * @notice Migrates the state from an old contract (stub implementation). * @param oldContract The address of the old contract to migrate state from. */ // solhint-disable-next-line no-empty-blocks function migrateStateFromContract(address oldContract) external {} }