Blockchain / Global / Address

Contract

0x54C9BDfF15b6EdEBF279e316D2D948DD6F53629b

Balance
0 SOMI
Transactions sent
1
Type
Contract · 1,884 bytes of code

FreezeThawLib Verified

Compiler
v0.8.22+commit.4fc1097e
Language
solidity
Optimization
Yes, 200 runs
EVM version
shanghai
License
none
Verified
2026-09-18

contracts/libraries/FreezeThawLib.sol

and 2 more files

solidity
pragma solidity ^0.8.0;

import {FreezeThawModule} from "contracts/modules/FreezeThawModule.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

/// @notice Freeze/thaw set mutations.
/// @dev Linked library. Runs via delegatecall against FreezeThawModule's namespaced storage.
///      Membership reads stay in the module — a delegatecall costs more than the lookup.
library FreezeThawLib {
    using EnumerableSet for EnumerableSet.AddressSet;

    /// @dev Must equal FreezeThawModule.FreezeThawStorageLocation.
    bytes32 private constant FreezeThawStorageLocation = 0xf6192aebe04228448ed4fd2802d59c009f5324cdd6a110c65bd318373b6e1d00;

    function _getFreezeThawStorage() private pure returns (FreezeThawModule.FreezeThawStorage storage $) {
        assembly {
            $.slot := FreezeThawStorageLocation
        }
    }

    function freeze(address account) public {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        $.frozen.add(account);
        emit FreezeThawModule.AccountFrozen(account);
    }

    function thaw(address account) public {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        $.frozen.remove(account);
        emit FreezeThawModule.AccountThawed(account);
    }

    function freezeMany(address[] calldata accounts) external {
        uint256 len = accounts.length;
        for (uint256 i; i < len; ++i) {
            freeze(accounts[i]);
        }
    }

    function thawMany(address[] calldata accounts) external {
        uint256 len = accounts.length;
        for (uint256 i; i < len; ++i) {
            thaw(accounts[i]);
        }
    }

    function addFreezer(address account) external {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        if (!$.freezers.add(account)) revert FreezeThawModule.AlreadyFreezer();
        emit FreezeThawModule.AddFreezer(account);
    }

    function removeFreezer(address account) external {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        if (!$.freezers.remove(account)) revert FreezeThawModule.NotFreezer();
        emit FreezeThawModule.RemoveFreezer(account);
    }




    function frozenList() external view returns (address[] memory) {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        return $.frozen.values();
    }

    function freezersList() external view returns (address[] memory) {
        FreezeThawModule.FreezeThawStorage storage $ = _getFreezeThawStorage();
        return $.freezers.values();
    }
}

Other files

  • contracts/modules/FreezeThawModule.sol
    pragma solidity ^0.8.0;
    
    import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
    import {FreezeThawLib} from "contracts/libraries/FreezeThawLib.sol";
    
    /**
     * @title FreezeThawModule
     * @dev Contract module that allows freezing and thawing of accounts.
     * @dev Set mutations are delegated to `FreezeThawLib`; membership reads are served locally.
     */
    abstract contract FreezeThawModule {
    
        using EnumerableSet for EnumerableSet.AddressSet;
    
        struct FreezeThawStorage {
            EnumerableSet.AddressSet freezers;
            EnumerableSet.AddressSet frozen;
        }
    
        /// @dev keccak256(abi.encode(uint256(keccak256("frax.storage.FreezeThawModule")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant FreezeThawStorageLocation = 0xf6192aebe04228448ed4fd2802d59c009f5324cdd6a110c65bd318373b6e1d00;
    
        function _getFreezeThawStorage() private pure returns (FreezeThawStorage storage $) {
            assembly {
                $.slot := FreezeThawStorageLocation
            }
        }
    
        /// @notice Internal helper function to freeze an account
        /// @param account The account to freeze
        /// @dev To be called externally by admin
        /// @dev Does not revert if the account is already frozen so that freezing always succeeds
        function _freeze(address account) internal virtual {
            FreezeThawLib.freeze(account);
        }
    
        /// @notice Internal helper function to unfreeze an account
        /// @param account The account to unfreeze
        /// @dev To be called externally by admin
        /// @dev Does not revert if the account is not frozen so that thawing always succeeds
        function _thaw(address account) internal virtual {
            FreezeThawLib.thaw(account);
        }
    
        /// @notice Internal helper function to freeze an array of accounts
        /// @param accounts The accounts to freeze
        /// @dev To be called externally by admin
        function _freezeMany(address[] calldata accounts) internal virtual {
            FreezeThawLib.freezeMany(accounts);
        }
    
        /// @notice Internal helper function to unfreeze an array of accounts
        /// @param accounts The accounts to be unfrozen
        /// @dev To be called externally by admin
        function _thawMany(address[] calldata accounts) internal virtual {
            FreezeThawLib.thawMany(accounts);
        }
    
        /// @notice Add a freezer role to an account
        /// @param account The account to add as a freezer
        /// @dev To be called externally by admin
        /// @dev Reverts if the account is already a freezer
        function _addFreezer(address account) internal virtual {
            FreezeThawLib.addFreezer(account);
        }
    
        /// @notice Remove a freezer role from an account
        /// @param account The account to remove as a freezer
        /// @dev To be called externally by admin
        /// @dev Reverts if the account is not a freezer
        function _removeFreezer(address account) internal virtual {
            FreezeThawLib.removeFreezer(account);
        }
    
        /// @notice Check if an account is frozen
        /// @param account The account to check
        /// @return bool True if the account is frozen, false otherwise
        function isFrozen(address account) public view virtual returns (bool) {
            FreezeThawStorage storage $ = _getFreezeThawStorage();
            return $.frozen.contains(account);
        }
    
        /// @notice Check if an account is an authorized freezer
        /// @param account The account to check
        /// @return bool True if the account is a freezer, false otherwise
        function isFreezer(address account) public view virtual returns (bool) {
            FreezeThawStorage storage $ =_getFreezeThawStorage();
            return $.freezers.contains(account);
        }
    
        /// @notice Get the list of all frozen accounts
        /// @return addres[] An array set of all frozen accounts
        function frozen() external view virtual returns (address[] memory) {
            return FreezeThawLib.frozenList();
        }
    
        /// @notice Get the list of all freezer accounts
        /// @return address[] An array set of all freezer accounts
        function freezers() external view virtual returns (address[] memory) {
            return FreezeThawLib.freezersList();
        }
    
        /* ========== EVENTS ========== */
        /// @notice Event Emitted when a freezer is aded
        /// @param account The account being added as a freezre
        event AddFreezer(address indexed account);
    
        /// @notice Event Emitted when a freezer is removed
        /// @param account The account being removed as a freezer
        event RemoveFreezer(address indexed account);
    
        /// @notice Event Emitted when an address is frozen
        /// @param account The account being frozen
        event AccountFrozen(address account);
    
        /// @notice Event Emitted when an address is unfrozen
        /// @param account The account being thawed
        event AccountThawed(address account);
    
        /* ========== ERRORS ========== */
        error AlreadyFreezer();
        error NotFreezer();
    }
    
  • node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol
    // 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;
        }
    }
    
ABI · 8 entries
json
[
  {
    "inputs": [],
    "name": "AlreadyFreezer",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotFreezer",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "AccountFrozen",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "AccountThawed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "AddFreezer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "RemoveFreezer",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "freezersList",
    "outputs": [
      {
        "internalType": "address[]",
        "name": "",
        "type": "address[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "frozenList",
    "outputs": [
      {
        "internalType": "address[]",
        "name": "",
        "type": "address[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]