SupplyControl

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/SupplyControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { AccessControlDefaultAdminRulesUpgradeable } from "./openzeppelin/contracts-upgradeable/access/AccessControlDefaultAdminRulesUpgradeable.sol";
import { UUPSUpgradeable } from "./openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { IAccessControl } from "./openzeppelin/contracts/access/IAccessControl.sol";
import { EnumerableSet } from "./openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { DoubleEndedQueue } from "./openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol";
import { PaxosBaseAbstract } from "./lib/PaxosBaseAbstract.sol";
import { RateLimit } from "./lib/RateLimit.sol";

/**
 * @title SupplyControl
 * @dev control the token supply. The `SUPPLY_CONTROLLER_MANAGER_ROLE` role is responsible for managing
 * addresses with the `SUPPLY_CONTROLLER_ROLE`, referred to as supplyControllers. Only supplyControllers can
 * mint and burn tokens. SupplyControllers can optionally have rate limits to limit how many tokens can be
 * minted over a given time frame.
 * @custom:security-contact smart-contract-security@paxos.com
 */
contract SupplyControl is AccessControlDefaultAdminRulesUpgradeable, UUPSUpgradeable {
    using EnumerableSet for EnumerableSet.AddressSet;
    // Access control roles
    // keccak256("SUPPLY_CONTROLLER_MANAGER_ROLE")
    // Can add, update, and remove `SupplyController`s
    bytes32 public constant SUPPLY_CONTROLLER_MANAGER_ROLE =
        0x5d3e9f1ecbcdad7b0da30e7d29c9eddaef83a4502dafe3d2dd85cfdb12e4af10;
    // keccak256("SUPPLY_CONTROLLER_ROLE")
    // Can mint/burn tokens
    bytes32 public constant SUPPLY_CONTROLLER_ROLE = 0x9c00d6f280439b1dfa4da90321e0a3f3c2e87280f4d07fea9fa43ff2cf02df2b;
    // keccak256("TOKEN_CONTRACT_ROLE")
    // Tracks the token contract to protect functions which impact rate limits
    bytes32 public constant TOKEN_CONTRACT_ROLE = 0xd32fd1ee5f4f111da6f27444787e5200ec57a8849509c00ef2998467052b32a3;

    // SUPPLY CONTROL DATA
    mapping(address => SupplyController) internal supplyControllerMap;

    //Used to get all supply controllers
    EnumerableSet.AddressSet internal supplyControllerSet;

    uint256[35] private __gap_SC; // solhint-disable-line var-name-mixedcase

    /**
     * @dev Struct defines a supply controller. Different supply controllers can have different rules.
     * @param rateLimit Contract which handles rate limit logic
     * @param mintAddressWhitelist Addresses the {SupplyController} can mint to
     * @param allowAnyMintAndBurnAddress If true, allows the supply controller to mint to and burn from any address
     */
    struct SupplyController {
        RateLimit.Storage rateLimitStorage;
        EnumerableSet.AddressSet mintAddressWhitelist;
        bool allowAnyMintAndBurnAddress;
    }

    /**
     * @dev Struct defines the configuration needed when creating a new supply controller.
     * @param newSupplyController Address of the new supply controller
     * @param limitConfig Limit configuration
     * @param mintAddressWhitelist Addresses the supply controller can mint to
     * @param allowAnyMintAndBurnAddress If true, allows the supply controller to mint to and burn from any address
     */
    struct SupplyControllerInitialization {
        address newSupplyController;
        RateLimit.LimitConfig limitConfig;
        address[] mintAddressWhitelist;
        bool allowAnyMintAndBurnAddress;
    }

    /**
     * @dev Emitted when {addSupplyController} is called.
     * @param newSupplyController Address of the new supply controller
     * @param limitCapacity Max amount for the rate limit. Checked in `_checkCurrentPeriodAmount`
     * @param refillPerSecond Amount to add to limit each second up to the `limitCapacity`
     * @param mintAddressWhitelist Addresses the supply controller can mint to
     * @param allowAnyMintAndBurnAddress If true, allows the supply controller to mint to and burn from any address
     */
    event SupplyControllerAdded(
        address indexed newSupplyController,
        uint256 limitCapacity,
        uint256 refillPerSecond,
        address[] mintAddressWhitelist,
        bool allowAnyMintAndBurnAddress
    );

    /**
     * @dev Emitted when {removeSupplyController} is called.
     * @param oldSupplyController The old supply controller address
     */
    event SupplyControllerRemoved(address indexed oldSupplyController);

    /**
     * @dev Emitted when limit configuration is updated for `supplyController`.
     * Occurs when {updateLimitConfig} is called.
     * @param supplyController Supply controller address
     * @param newLimitConfig New limit configuration
     * @param oldLimitConfig Old limit configuration
     */
    event LimitConfigUpdated(
        address indexed supplyController,
        RateLimit.LimitConfig newLimitConfig,
        RateLimit.LimitConfig oldLimitConfig
    );

    /**
     * @dev Emitted when `allowAnyMintAndBurnAddress` is updated for `supplyController`.
     * Occurs when {updateAllowAnyMintAndBurnAddress} is called.
     * @param supplyController Supply controller address
     * @param newAllowAnyMintAndBurnAddress New allow config
     * @param oldAllowAnyMintAndBurnAddress Old allow config
     */
    event AllowAnyMintAndBurnAddressUpdated(
        address indexed supplyController,
        bool newAllowAnyMintAndBurnAddress,
        bool oldAllowAnyMintAndBurnAddress
    );

    /**
     * @dev Emitted when `mintAddress` is added to `mintAddressWhitelist` in `supplyController`.
     * Occurs when {addMintAddressToWhitelist} is called
     * @param supplyController Supply controller address
     * @param mintAddress New address which can be minted to
     */
    event MintAddressAddedToWhitelist(address indexed supplyController, address indexed mintAddress);

    /**
     * @dev Emitted when `mintAddress` is removed from `mintAddressWhitelist` in `supplyController`.
     * Occurs when {removeMintAddressFromWhitelist} is called
     * @param supplyController Supply controller address
     * @param mintAddress Address which can no longer be minted to
     */
    event MintAddressRemovedFromWhitelist(address indexed supplyController, address indexed mintAddress);

    error AccountMissingSupplyControllerRole(address account);
    error AccountAlreadyHasSupplyControllerRole(address account);
    error CannotMintToAddress(address supplyController, address mintToAddress);
    error CannotBurnFromAddress(address supplyController, address burnFromAddress);
    error CannotAddDuplicateAddress(address addressToAdd);
    error CannotRemoveNonExistantAddress(address addressToRemove);
    error ZeroAddress();

    /**
     * @dev Modifier which checks that the specified `supplyController` address has the SUPPLY_CONTROLLER_ROLE
     * @param supplyController Supply controller address
     */
    modifier onlySupplyController(address supplyController) {
        if (!hasRole(SUPPLY_CONTROLLER_ROLE, supplyController)) {
            revert AccountMissingSupplyControllerRole(supplyController);
        }
        _;
    }

    /**
     * @dev Modifier which checks that the specified `supplyController` address does not have the SUPPLY_CONTROLLER_ROLE
     * @param supplyController Supply controller address
     */
    modifier notSupplyController(address supplyController) {
        if (hasRole(SUPPLY_CONTROLLER_ROLE, supplyController)) {
            revert AccountAlreadyHasSupplyControllerRole(supplyController);
        }
        _;
    }

    /**
     * @dev Modifier to check for zero address.
     */
    modifier isNonZeroAddress(address addr) {
        if (addr == address(0)) {
            revert ZeroAddress();
        }
        _;
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /**
     * @dev Initializer for SupplyControl.
     * Proper order of setting up the contracts:
     *  1. Deploy/reinitialize PaxosToken
     *  2. Deploy SupplyControl with `SupplyControllerInitialization` config
     *  3. Set SupplyControl address in PaxosToken via `setSupplyControl`
     * @param initialOwner Initial owner address
     * @param supplyControllerManager SupplyControllerManager address
     * @param tokenAddress Token contract address
     * @param scInitializationConfig Configuration to initialize a list of supply controllers
     */
    function initialize(
        address initialOwner,
        address supplyControllerManager,
        address tokenAddress,
        SupplyControllerInitialization[] calldata scInitializationConfig
    ) external initializer isNonZeroAddress(supplyControllerManager) isNonZeroAddress(tokenAddress) {
        __AccessControlDefaultAdminRules_init(3 hours, initialOwner);
        __UUPSUpgradeable_init();
        _grantRole(SUPPLY_CONTROLLER_MANAGER_ROLE, supplyControllerManager);
        _grantRole(TOKEN_CONTRACT_ROLE, tokenAddress);
        for (uint256 i = 0; i < scInitializationConfig.length; ) {
            _addSupplyController(scInitializationConfig[i]);
            unchecked {
                i++;
            }
        }
    }

    /**
     * @dev Adds a new supply controller which can be used to control the supply of a token.
     * Can be called externally by the `SUPPLY_CONTROLLER_MANAGER_ROLE`.
     * @param newSupplyController Address of the new supply controller
     * @param limitCapacity Max amount for the rate limit.
     * @param refillPerSecond Amount to add to limit each second up to the `limitCapacity`
     * @param mintAddressWhitelist Addresses the supply controller can mint to
     * @param allowAnyMintAndBurnAddress If true, allows the supply controller to mint to and burn from any address
     */
    function addSupplyController(
        address newSupplyController,
        uint256 limitCapacity,
        uint256 refillPerSecond,
        address[] memory mintAddressWhitelist,
        bool allowAnyMintAndBurnAddress
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) {
        RateLimit.LimitConfig memory limitConfig = RateLimit.LimitConfig(limitCapacity, refillPerSecond);
        SupplyControllerInitialization memory scInitializationConfig = SupplyControllerInitialization(
            newSupplyController,
            limitConfig,
            mintAddressWhitelist,
            allowAnyMintAndBurnAddress
        );
        _addSupplyController(scInitializationConfig);
    }

    /**
     * @dev Removes `oldSupplyController`
     * @param oldSupplyController The old supply controller address
     */
    function removeSupplyController(
        address oldSupplyController
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) onlySupplyController(oldSupplyController) {
        _revokeRole(SUPPLY_CONTROLLER_ROLE, oldSupplyController);
        SupplyController storage supplyController = supplyControllerMap[oldSupplyController];
        _removeAddressSet(supplyController.mintAddressWhitelist);
        EnumerableSet.remove(supplyControllerSet, oldSupplyController);
        delete supplyControllerMap[oldSupplyController];
        emit SupplyControllerRemoved(oldSupplyController);
    }

    /**
     * Update limit configuration
     * @param supplyController_ Supply controller address.
     * @param limitCapacity Max amount for the rate limit
     * @param refillPerSecond Amount to add to limit each second up to the `limitCapacity`
     */
    function updateLimitConfig(
        address supplyController_,
        uint256 limitCapacity,
        uint256 refillPerSecond
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) onlySupplyController(supplyController_) {
        RateLimit.LimitConfig memory limitConfig = RateLimit.LimitConfig(limitCapacity, refillPerSecond);
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        RateLimit.LimitConfig memory oldLimitConfig = supplyController.rateLimitStorage.limitConfig;
        supplyController.rateLimitStorage.limitConfig = limitConfig;
        emit LimitConfigUpdated(supplyController_, limitConfig, oldLimitConfig);
    }

    function updateAllowAnyMintAndBurnAddress(
        address supplyController_,
        bool allowAnyMintAndBurnAddress
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) onlySupplyController(supplyController_) {
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        bool oldAllowValue = supplyController.allowAnyMintAndBurnAddress;
        supplyController.allowAnyMintAndBurnAddress = allowAnyMintAndBurnAddress;
        emit AllowAnyMintAndBurnAddressUpdated(supplyController_, allowAnyMintAndBurnAddress, oldAllowValue);
    }

    /**
     * @dev Adds `mintAddress` to `mintAddressWhitelist` in `supplyController`.
     * @param supplyController_ Supply controller address
     * @param mintAddress Address which can be minted to
     */
    function addMintAddressToWhitelist(
        address supplyController_,
        address mintAddress
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) onlySupplyController(supplyController_) {
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        if (EnumerableSet.contains(supplyController.mintAddressWhitelist, mintAddress)) {
            revert CannotAddDuplicateAddress(mintAddress);
        }
        EnumerableSet.add(supplyController.mintAddressWhitelist, mintAddress);
        emit MintAddressAddedToWhitelist(supplyController_, mintAddress);
    }

    /**
     * @dev Removes `mintAddress` from `mintAddressWhitelist` in `supplyController`.
     * @param supplyController_ Supply controller address
     * @param mintAddress Address which can no longer be minted to
     */
    function removeMintAddressFromWhitelist(
        address supplyController_,
        address mintAddress
    ) external onlyRole(SUPPLY_CONTROLLER_MANAGER_ROLE) onlySupplyController(supplyController_) {
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        if (!EnumerableSet.contains(supplyController.mintAddressWhitelist, mintAddress)) {
            revert CannotRemoveNonExistantAddress(mintAddress);
        }

        EnumerableSet.remove(supplyController.mintAddressWhitelist, mintAddress);
        emit MintAddressRemovedFromWhitelist(supplyController_, mintAddress);
    }

    /**
     * @dev Gets supply controller configuration
     * @param supplyController_ Supply controller address
     */
    function getSupplyControllerConfig(
        address supplyController_
    )
        external
        view
        onlySupplyController(supplyController_)
        returns (
            RateLimit.LimitConfig memory limitConfig,
            address[] memory mintAddressWhitelist,
            bool allowAnyMintAndBurnAddress
        )
    {
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        RateLimit.LimitConfig memory limitConfig_ = supplyController.rateLimitStorage.limitConfig;
        address[] memory mintAddressWhitelist_ = EnumerableSet.values(
            supplyControllerMap[supplyController_].mintAddressWhitelist
        );
        return (limitConfig_, mintAddressWhitelist_, supplyController.allowAnyMintAndBurnAddress);
    }

    /**
     * @dev Gets all supply controller addresses
     */
    function getAllSupplyControllerAddresses() external view returns (address[] memory) {
        return EnumerableSet.values(supplyControllerSet);
    }

    /**
     * @dev Get remaining amount which can be minted at `timestamp`
     * @param supplyController_ Supply controller address
     * @param timestamp Time to check remaining amount for
     */
    function getRemainingMintAmount(
        address supplyController_,
        uint256 timestamp
    ) external view onlySupplyController(supplyController_) returns (uint256) {
        SupplyController storage supplyController = supplyControllerMap[supplyController_];
        RateLimit.Storage storage limitStorage = supplyController.rateLimitStorage;
        return RateLimit.getRemainingAmount(timestamp, limitStorage);
    }

    /**
     * @dev Function which checks that `mintToAddress` is in the whitelisted map for msg.sender
     * and the amount does not exceed the rate limit
     * @param mintToAddress Mint to address
     * @param amount Amount to check
     * @param sender Supply controller address
     */
    function canMintToAddress(
        address mintToAddress,
        uint256 amount,
        address sender
    ) external onlySupplyController(sender) onlyRole(TOKEN_CONTRACT_ROLE) {
        SupplyController storage supplyController = supplyControllerMap[sender];
        if (
            !supplyController.allowAnyMintAndBurnAddress &&
            !EnumerableSet.contains(supplyController.mintAddressWhitelist, mintToAddress)
        ) {
            revert CannotMintToAddress(sender, mintToAddress);
        }
        RateLimit.Storage storage limitStorage = supplyController.rateLimitStorage;
        RateLimit.checkNewEvent(block.timestamp, amount, limitStorage);
    }

    /**
     * @dev Function which checks that `burnFromAddress` is the 'sender' or that the 'sender' is allowed to burn
     * from any address.
     * Also checks that the `sender` is a supply controller since only a supply controller can burn tokens.
     * @param burnFromAddress Burn from address
     * @param sender Supply controller address
     */
    function canBurnFromAddress(address burnFromAddress, address sender) external view onlySupplyController(sender) {
        SupplyController storage supplyController = supplyControllerMap[sender];
        if (!supplyController.allowAnyMintAndBurnAddress && sender != burnFromAddress) {
            revert CannotBurnFromAddress(sender, burnFromAddress);
        }
    }

    /**
     * @dev Adds a new supply controller which can be used to control the supply of a token.
     * Can only be called internally.
     * @param scInitializationConfig Configuration to setup a new supply controller
     */
    function _addSupplyController(
        SupplyControllerInitialization memory scInitializationConfig
    )
        internal
        notSupplyController(scInitializationConfig.newSupplyController)
        isNonZeroAddress(scInitializationConfig.newSupplyController)
    {
        SupplyController storage supplyController = supplyControllerMap[scInitializationConfig.newSupplyController];
        supplyController.rateLimitStorage.limitConfig = scInitializationConfig.limitConfig;
        supplyController.allowAnyMintAndBurnAddress = scInitializationConfig.allowAnyMintAndBurnAddress;
        _addressArrayToSet(scInitializationConfig.mintAddressWhitelist, supplyController.mintAddressWhitelist);
        _grantRole(SUPPLY_CONTROLLER_ROLE, scInitializationConfig.newSupplyController);
        EnumerableSet.add(supplyControllerSet, scInitializationConfig.newSupplyController);
        emit SupplyControllerAdded(
            scInitializationConfig.newSupplyController,
            scInitializationConfig.limitConfig.limitCapacity,
            scInitializationConfig.limitConfig.refillPerSecond,
            scInitializationConfig.mintAddressWhitelist,
            scInitializationConfig.allowAnyMintAndBurnAddress
        );
    }

    /**
     * @dev required by the OZ UUPS module to authorize an upgrade
     * of the contract. Restricted to DEFAULT_ADMIN_ROLE.
     */
    function _authorizeUpgrade(address) internal override onlyRole(DEFAULT_ADMIN_ROLE) {} // solhint-disable-line no-empty-blocks

    /**
     * @dev Helper function for setting `mintAddressWhitelist`
     * @param addressArray Array containing mint addresses
     * @param addressSet Set which addresses should be added to
     */
    function _addressArrayToSet(address[] memory addressArray, EnumerableSet.AddressSet storage addressSet) private {
        for (uint256 i = 0; i < addressArray.length; ) {
            EnumerableSet.add(addressSet, addressArray[i]);
            unchecked {
                i++;
            }
        }
    }

    /**
     * @dev Helper function for removing all addresses from `mintAddressWhitelist`
     * Removes elements in reverse order to reduce array reordering and improve gas efficiency
     * @param addressSet Set of addresses
     */
    function _removeAddressSet(EnumerableSet.AddressSet storage addressSet) private {
        uint256 length = EnumerableSet.length(addressSet);
        for (uint256 i = length; i > 0; ) {
            unchecked {
                i--;
            }
            EnumerableSet.remove(addressSet, EnumerableSet.at(addressSet, i));
        }
    }
}
"
    },
    "contracts/lib/RateLimit.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { DoubleEndedQueue } from "@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "hardhat/console.sol";

/**
 * @title RateLimit library
 * @dev Performs rate limiting using an elapsed time algorithm
 * @custom:security-contact smart-contract-security@paxos.com
 */
library RateLimit {
    uint256 constant SKIP_RATE_LIMIT_CHECK = 0;
    struct Storage {
        // Limit configuration
        LimitConfig limitConfig;
        // Remaining amount for the time period
        uint256 remainingAmount;
        //Timestamp of last event
        uint256 lastRefillTime;
    }
    struct LimitConfig {
        // Max amount for the rate limit
        uint256 limitCapacity;
        // Amount to add to limit each second up to the limitCapacity
        uint256 refillPerSecond;
    }

    error RateLimitExceeded();
    error OldTimestamp(uint256 timestamp, uint256 expected);

    /**
     * @dev Uses an elapsed time algorithm to determine if the new event is allowed or not.
     * High level steps:
     *   1. Calculate elapsed time since last event
     *   2. Calculate amount that can be sent at the current `timestamp`
     *   3. Check if rate limit is exceeded or not and update remaining amount
     *
     * @param timestamp Timestamp of the new event
     * @param amount Amount of the new event
     * @param limitStorage Storage data specific to the rate limit check
     */
    function checkNewEvent(uint256 timestamp, uint256 amount, Storage storage limitStorage) internal {
        //Limit time period of 0 is a special value indicating we should skip rate limit checking
        if (limitStorage.limitConfig.refillPerSecond == SKIP_RATE_LIMIT_CHECK) {
            return;
        }
        limitStorage.remainingAmount = refill(timestamp, limitStorage);
        limitStorage.lastRefillTime = timestamp;
        if (amount > limitStorage.remainingAmount) {
            revert RateLimitExceeded();
        }
        limitStorage.remainingAmount -= amount;
    }

    /**
     * @dev Gets remaining amount that can be sent in the window
     * @param timestamp Timestamp to check remaining amount for
     * @param limitStorage Storage data specific to the rate limit check
     */
    function getRemainingAmount(uint256 timestamp, Storage storage limitStorage) internal view returns (uint256) {
        // Limit time period of 0 is a special value indicating we should skip rate limit checking
        if (limitStorage.limitConfig.refillPerSecond == SKIP_RATE_LIMIT_CHECK) {
            return type(uint256).max;
        }
        return refill(timestamp, limitStorage);
    }

    /**
     * @dev Refills the amount based on the elapsed time from the previous event.
     * `timestamp` cannot be older than the `lastRefillTime`.
     * @param timestamp Timestamp of the new event
     * @param limitStorage Storage data specific to the rate limit check
     */
    function refill(uint256 timestamp, Storage storage limitStorage) private view returns (uint256) {
        if (limitStorage.lastRefillTime > timestamp) {
            revert OldTimestamp(timestamp, limitStorage.lastRefillTime);
        }
        uint256 secondsElapsed = timestamp - limitStorage.lastRefillTime;
        (bool safeMul, uint256 newTokens) = SafeMath.tryMul(secondsElapsed, limitStorage.limitConfig.refillPerSecond);
        (bool safeAdd, uint256 amount) = SafeMath.tryAdd(limitStorage.remainingAmount, newTokens);
        if (!safeMul || !safeAdd) {
            return limitStorage.limitConfig.limitCapacity;
        }
        return Math.min(limitStorage.limitConfig.limitCapacity, amount);
    }
}
"
    },
    "contracts/lib/PaxosBaseAbstract.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @title PaxosBaseAbstract contract
 * @dev An abstract contract for Paxos tokens with additional internal functions.
 * @custom:security-contact smart-contract-security@paxos.com
 */
abstract contract PaxosBaseAbstract {
    // keccak256("PAUSE_ROLE")
    bytes32 public constant PAUSE_ROLE = 0x139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d;
    // keccak256("ASSET_PROTECTION_ROLE")
    bytes32 public constant ASSET_PROTECTION_ROLE = 0xe3e4f9d7569515307c0cdec302af069a93c9e33f325269bac70e6e22465a9796;

    // All base errors.
    error ZeroAddress();
    error ContractPaused();
    error AddressFrozen();
    error InvalidPermission();
    error AccessControlUnauthorizedAccount(address account, bytes32 role);
    error InvalidSignature();
    error ArgumentLengthMismatch();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        if (_isPaused()) revert ContractPaused();
        _;
    }

    /**
     * @dev Modifier to check for zero address.
     */
    modifier isNonZeroAddress(address addr) {
        if (addr == address(0)) revert ZeroAddress();
        _;
    }

    /*
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return "PaxosToken USD";
    }

    /*
     * @dev Returns the symbol of the token.
     */
    function symbol() public view virtual returns (string memory) {
        return "PaxosToken";
    }

    /*
     * @dev Returns the decimal count of the token.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev Set allowance for a given spender, of a given owner.
     * @param owner address The address which owns the funds.
     * @param spender address The address which will spend the funds.
     * @param value uint256 The amount of tokens to increase the allowance by.
     */
    function _approve(address owner, address spender, uint256 value) internal virtual;

    /**
     * @dev Transfer `value` amount `from` => `to`.
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to send tokens to
     * @param value uint256 the amount of tokens to be transferred
     */
    function _transfer(address from, address to, uint256 value) internal virtual;

    /**
     * @dev Check if contract is paused.
     * @return bool True if the contract is paused, false otherwise.
     */
    function _isPaused() internal view virtual returns (bool);

    /**
     * @dev Internal function to check whether the address is currently frozen by checking
     * the sanctioned list first.
     * @param addr The address to check if frozen.
     * @return A bool representing whether the given address is frozen.
     */
    function _isAddrFrozen(address addr) internal view virtual returns (bool);
}
"
    },
    "contracts/openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/DoubleEndedQueue.sol)
pragma solidity ^0.8.4;

import "../math/SafeCast.sol";

/**
 * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
 * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
 * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
 * the existing queue contents are left in storage.
 *
 * The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be
 * used in storage, and not in memory.
 * ```solidity
 * DoubleEndedQueue.Bytes32Deque queue;
 * ```
 *
 * _Available since v4.6._
 */
library DoubleEndedQueue {
    /**
     * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
     */
    error Empty();

    /**
     * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
     */
    error OutOfBounds();

    /**
     * @dev Indices are signed integers because the queue can grow in any direction. They are 128 bits so begin and end
     * are packed in a single storage slot for efficient access. Since the items are added one at a time we can safely
     * assume that these 128-bit indices will not overflow, and use unchecked arithmetic.
     *
     * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
     * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
     * lead to unexpected behavior.
     *
     * Indices are in the range [begin, end) which means the first item is at data[begin] and the last item is at
     * data[end - 1].
     */
    struct Bytes32Deque {
        int128 _begin;
        int128 _end;
        mapping(int128 => bytes32) _data;
    }

    /**
     * @dev Inserts an item at the end of the queue.
     */
    function pushBack(Bytes32Deque storage deque, bytes32 value) internal {
        int128 backIndex = deque._end;
        deque._data[backIndex] = value;
        unchecked {
            deque._end = backIndex + 1;
        }
    }

    /**
     * @dev Removes the item at the end of the queue and returns it.
     *
     * Reverts with `Empty` if the queue is empty.
     */
    function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) {
        if (empty(deque)) revert Empty();
        int128 backIndex;
        unchecked {
            backIndex = deque._end - 1;
        }
        value = deque._data[backIndex];
        delete deque._data[backIndex];
        deque._end = backIndex;
    }

    /**
     * @dev Inserts an item at the beginning of the queue.
     */
    function pushFront(Bytes32Deque storage deque, bytes32 value) internal {
        int128 frontIndex;
        unchecked {
            frontIndex = deque._begin - 1;
        }
        deque._data[frontIndex] = value;
        deque._begin = frontIndex;
    }

    /**
     * @dev Removes the item at the beginning of the queue and returns it.
     *
     * Reverts with `Empty` if the queue is empty.
     */
    function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) {
        if (empty(deque)) revert Empty();
        int128 frontIndex = deque._begin;
        value = deque._data[frontIndex];
        delete deque._data[frontIndex];
        unchecked {
            deque._begin = frontIndex + 1;
        }
    }

    /**
     * @dev Returns the item at the beginning of the queue.
     *
     * Reverts with `Empty` if the queue is empty.
     */
    function front(Bytes32Deque storage deque) internal view returns (bytes32 value) {
        if (empty(deque)) revert Empty();
        int128 frontIndex = deque._begin;
        return deque._data[frontIndex];
    }

    /**
     * @dev Returns the item at the end of the queue.
     *
     * Reverts with `Empty` if the queue is empty.
     */
    function back(Bytes32Deque storage deque) internal view returns (bytes32 value) {
        if (empty(deque)) revert Empty();
        int128 backIndex;
        unchecked {
            backIndex = deque._end - 1;
        }
        return deque._data[backIndex];
    }

    /**
     * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
     * `length(deque) - 1`.
     *
     * Reverts with `OutOfBounds` if the index is out of bounds.
     */
    function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) {
        // int256(deque._begin) is a safe upcast
        int128 idx = SafeCast.toInt128(int256(deque._begin) + SafeCast.toInt256(index));
        if (idx >= deque._end) revert OutOfBounds();
        return deque._data[idx];
    }

    /**
     * @dev Resets the queue back to being empty.
     *
     * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
     * out on potential gas refunds.
     */
    function clear(Bytes32Deque storage deque) internal {
        deque._begin = 0;
        deque._end = 0;
    }

    /**
     * @dev Returns the number of items in the queue.
     */
    function length(Bytes32Deque storage deque) internal view returns (uint256) {
        // The interface preserves the invariant that begin <= end so we assume this will not overflow.
        // We also assume there are at most int256.max items in the queue.
        unchecked {
            return uint256(int256(deque._end) - int256(deque._begin));
        }
    }

    /**
     * @dev Returns true if the queue is empty.
     */
    function empty(Bytes32Deque storage deque) internal view returns (bool) {
        return deque._end <= deque._begin;
    }
}
"
    },
    "contracts/openzeppelin/contracts/utils/structs/EnumerableSet.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
"
    },
    "contracts/openzeppelin/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}
"
    },
    "contracts/openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeTo(address newImplementation) public virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
"
    },
    "contracts/openzeppelin/contracts-upgradeable/access/AccessControlDefaultAdminRulesUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControlDefaultAdminRules.sol)

pragma solidity ^0.8.0;

import "./AccessControlUpgradeable.sol";
import "./IAccessControlDefaultAdminRulesUpgradeable.sol";
import "../utils/math/SafeCastUpgradeable.sol";
import "../interfaces/IERC5313Upgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {AccessControl} that allows specifying special rules to manage
 * the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
 * over other roles that may potentially have privileged rights in the system.
 *
 * If a specific role doesn't have an admin role assigned, the holder of the
 * `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
 *
 * This contract implements the following risk mitigations on top of {AccessControl}:
 *
 * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
 * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
 * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
 * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
 * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
 *
 * Example usage:
 *
 * ```solidity
 * contract MyToken is AccessControlDefaultAdminRules {
 *   constructor() AccessControlDefaultAdminRules(
 *     3 days,
 *     msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
 *    ) {}
 * }
 * ```
 *
 * _Available since v4.9._
 */
abstract contract AccessControlDefaultAdminRulesUpgradeable is Initializable, IAccessControlDefaultAdminRulesUpgradeable, IERC5313Upgradeable, AccessControlUpgradeable {
    // pending admin pair read/written together frequently
    address private _pendingDefaultAdmin;
    uint48 private _pendingDefaultAdminSchedule; // 0 == unset

    uint48 private _currentDelay;
    address private _currentDefaultAdmin;

    // pending delay pair read/written together frequently
    uint48 private _pendingDelay;
    uint48 private _pendingDelaySchedule; // 0 == unset

    /**
     * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
     */
    function __AccessControlDefaultAdminRules_init(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
        __AccessControlDefaultAdminRules_init_unchained(initialDelay, initialDefaultAdmin);
    }

    function __AccessControlDefaultAdminRules_init_unchained(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
        require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin");
        _currentDelay = initialDelay;
        _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlDefaultAdminRulesUpgradeable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC5313-owner}.
     */
    function owner() public view virtual returns (address) {
        return defaultAdmin();
    }

    ///
    /// Override AccessControl role management
    ///

    /**
     * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
     */
    function grantRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
        require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly grant default admin role");
        super.grantRole(role, account);
    }

    /**
     * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
     */
    function revokeRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
        require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly revoke default admin role");
        super.revokeRole(role, account);
    }

    /**
     * @dev See {AccessControl-renounceRole}.
     *
     * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
     * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
     * has also passed when calling this function.
     *
     * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
     *
     * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
     * thereby disabling any functionality that is only available for it, and the possibility of reassigning a
     * non-administrated role.
     */
    function renounceRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControlUpgradeable) {
        if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
            (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
            require(
                newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule),
                "AccessControl: only can renounce in two delayed steps"
            );
            delete _pendingDefaultAdminSchedule;
        }
        super.renounceRole(role, account);
    }

    /**
     * @dev See {AccessControl-_grantRole}.
     *
     * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
     * role has been previously renounced.
     *
     * NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`
     * assignable again. Make sure to guarantee this is the expected behavior in your implementation.
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        if (role == DEFAULT_ADMIN_ROLE) {
            require(defaultAdmin() == address(0), "AccessControl: default admin already granted");
            _currentDefaultAdmin = account;
        }
        super._grantRole(role, account);
    }

    /**
     * @dev See {AccessControl-_revokeRole}.
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
            delete _currentDefaultAdmin;
        }
        super._revokeRole(role, account);
    }

    /**
     * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
        require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules");
        super._setRoleAdmin(role, adminRole);
    }

    ///
    /// AccessControlDefaultAdminRules accessors
    ///

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function defaultAdmin() public view virtual returns (address) {
        return _currentDefaultAdmin;
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
        return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function defaultAdminDelay() public view virtual returns (uint48) {
        uint48 schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay;
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
        schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
        return 5 days;
    }

    ///
    /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
    ///

    /**
     * @inheritdoc IAccessControlDefaultAdminRulesUpgradeable
     */
    function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _beginDefaultAdminTransfer(newAdmin);
    }

    /**
     * @dev See {beginDefaultAdminTransfer}.
     *
     * Internal function without access restriction.
     */
    function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
        uint48 newSchedule = SafeCastUpgradeable.toUint48(block.timestamp) + defaultAdminDelay();
        _setPendingDefaultAdmin(newAdmin, newSchedu

Tags:
ERC165, Multisig, Upgradeable, Multi-Signature, Factory|addr:0x27201a8dbc258ebd7dedae54410d3769cc8d5f1f|verified:true|block:23649510|tx:0x2c31c87aaaca139c18ce66e2a3f33d044f4f2723b23250e57cd1aed4257b26e7|first_check:1761336942

Submitted on: 2025-10-24 22:15:44

Comments

Log in to comment.

No comments yet.