{"sources":{"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n    struct OwnableStorage {\n        address _owner;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n        assembly {\n            $.slot := OwnableStorageLocation\n        }\n    }\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    function __Ownable_init(address initialOwner) internal onlyInitializing {\n        __Ownable_init_unchained(initialOwner);\n    }\n\n    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        OwnableStorage storage $ = _getOwnableStorage();\n        return $._owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        OwnableStorage storage $ = _getOwnableStorage();\n        address oldOwner = $._owner;\n        $._owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reininitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        assembly {\n            $.slot := INITIALIZABLE_STORAGE\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC1822Proxiable} from \"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\";\nimport {ERC1967Utils} from \"@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol\";\nimport {Initializable} from \"./Initializable.sol\";\n\n/**\n * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an\n * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.\n *\n * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is\n * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing\n * `UUPSUpgradeable` with a custom implementation of upgrades.\n *\n * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.\n */\nabstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address private immutable __self = address(this);\n\n    /**\n     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`\n     * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,\n     * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.\n     * If the getter returns `\"5.0.0\"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must\n     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function\n     * during an upgrade.\n     */\n    string public constant UPGRADE_INTERFACE_VERSION = \"5.0.0\";\n\n    /**\n     * @dev The call is from an unauthorized context.\n     */\n    error UUPSUnauthorizedCallContext();\n\n    /**\n     * @dev The storage `slot` is unsupported as a UUID.\n     */\n    error UUPSUnsupportedProxiableUUID(bytes32 slot);\n\n    /**\n     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is\n     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case\n     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a\n     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to\n     * fail.\n     */\n    modifier onlyProxy() {\n        _checkProxy();\n        _;\n    }\n\n    /**\n     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be\n     * callable on the implementing contract but not through proxies.\n     */\n    modifier notDelegated() {\n        _checkNotDelegated();\n        _;\n    }\n\n    function __UUPSUpgradeable_init() internal onlyInitializing {\n    }\n\n    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the\n     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.\n     *\n     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.\n     */\n    function proxiableUUID() external view virtual notDelegated returns (bytes32) {\n        return ERC1967Utils.IMPLEMENTATION_SLOT;\n    }\n\n    /**\n     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call\n     * encoded in `data`.\n     *\n     * Calls {_authorizeUpgrade}.\n     *\n     * Emits an {Upgraded} event.\n     *\n     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall\n     */\n    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {\n        _authorizeUpgrade(newImplementation);\n        _upgradeToAndCallUUPS(newImplementation, data);\n    }\n\n    /**\n     * @dev Reverts if the execution is not performed via delegatecall or the execution\n     * context is not of a proxy with an ERC1967-compliant implementation pointing to self.\n     * See {_onlyProxy}.\n     */\n    function _checkProxy() internal view virtual {\n        if (\n            address(this) == __self || // Must be called through delegatecall\n            ERC1967Utils.getImplementation() != __self // Must be called through an active proxy\n        ) {\n            revert UUPSUnauthorizedCallContext();\n        }\n    }\n\n    /**\n     * @dev Reverts if the execution is performed via delegatecall.\n     * See {notDelegated}.\n     */\n    function _checkNotDelegated() internal view virtual {\n        if (address(this) != __self) {\n            // Must not be called through delegatecall\n            revert UUPSUnauthorizedCallContext();\n        }\n    }\n\n    /**\n     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by\n     * {upgradeToAndCall}.\n     *\n     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.\n     *\n     * ```solidity\n     * function _authorizeUpgrade(address) internal onlyOwner {}\n     * ```\n     */\n    function _authorizeUpgrade(address newImplementation) internal virtual;\n\n    /**\n     * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.\n     *\n     * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value\n     * is expected to be the implementation slot in ERC1967.\n     *\n     * Emits an {IERC1967-Upgraded} event.\n     */\n    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {\n        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n            if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {\n                revert UUPSUnsupportedProxiableUUID(slot);\n            }\n            ERC1967Utils.upgradeToAndCall(newImplementation, data);\n        } catch {\n            // The implementation is not UUPS\n            revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},"@openzeppelin/contracts/interfaces/draft-IERC1822.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n    /**\n     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n     * address.\n     *\n     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n     * function revert if invoked through a proxy.\n     */\n    function proxiableUUID() external view returns (bytes32);\n}\n"},"@openzeppelin/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"@openzeppelin/contracts/proxy/beacon/IBeacon.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n    /**\n     * @dev Must return an address that can be used as a delegate call target.\n     *\n     * {UpgradeableBeacon} will check that this address is a contract.\n     */\n    function implementation() external view returns (address);\n}\n"},"@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)\n\npragma solidity ^0.8.20;\n\nimport {IBeacon} from \"../beacon/IBeacon.sol\";\nimport {Address} from \"../../utils/Address.sol\";\nimport {StorageSlot} from \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n */\nlibrary ERC1967Utils {\n    // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.\n    // This will be fixed in Solidity 0.8.21. At that point we should remove these events.\n    /**\n     * @dev Emitted when the implementation is upgraded.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Emitted when the admin account has changed.\n     */\n    event AdminChanged(address previousAdmin, address newAdmin);\n\n    /**\n     * @dev Emitted when the beacon is changed.\n     */\n    event BeaconUpgraded(address indexed beacon);\n\n    /**\n     * @dev Storage slot with the address of the current implementation.\n     * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1.\n     */\n    // solhint-disable-next-line private-vars-leading-underscore\n    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /**\n     * @dev The `implementation` of the proxy is invalid.\n     */\n    error ERC1967InvalidImplementation(address implementation);\n\n    /**\n     * @dev The `admin` of the proxy is invalid.\n     */\n    error ERC1967InvalidAdmin(address admin);\n\n    /**\n     * @dev The `beacon` of the proxy is invalid.\n     */\n    error ERC1967InvalidBeacon(address beacon);\n\n    /**\n     * @dev An upgrade function sees `msg.value > 0` that may be lost.\n     */\n    error ERC1967NonPayable();\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function getImplementation() internal view returns (address) {\n        return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 implementation slot.\n     */\n    function _setImplementation(address newImplementation) private {\n        if (newImplementation.code.length == 0) {\n            revert ERC1967InvalidImplementation(newImplementation);\n        }\n        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;\n    }\n\n    /**\n     * @dev Performs implementation upgrade with additional setup call if data is nonempty.\n     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected\n     * to avoid stuck value in the contract.\n     *\n     * Emits an {IERC1967-Upgraded} event.\n     */\n    function upgradeToAndCall(address newImplementation, bytes memory data) internal {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n\n        if (data.length > 0) {\n            Address.functionDelegateCall(newImplementation, data);\n        } else {\n            _checkNonPayable();\n        }\n    }\n\n    /**\n     * @dev Storage slot with the admin of the contract.\n     * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1.\n     */\n    // solhint-disable-next-line private-vars-leading-underscore\n    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n    /**\n     * @dev Returns the current admin.\n     *\n     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using\n     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\n     */\n    function getAdmin() internal view returns (address) {\n        return StorageSlot.getAddressSlot(ADMIN_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 admin slot.\n     */\n    function _setAdmin(address newAdmin) private {\n        if (newAdmin == address(0)) {\n            revert ERC1967InvalidAdmin(address(0));\n        }\n        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {IERC1967-AdminChanged} event.\n     */\n    function changeAdmin(address newAdmin) internal {\n        emit AdminChanged(getAdmin(), newAdmin);\n        _setAdmin(newAdmin);\n    }\n\n    /**\n     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n     * This is the keccak-256 hash of \"eip1967.proxy.beacon\" subtracted by 1.\n     */\n    // solhint-disable-next-line private-vars-leading-underscore\n    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n    /**\n     * @dev Returns the current beacon.\n     */\n    function getBeacon() internal view returns (address) {\n        return StorageSlot.getAddressSlot(BEACON_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new beacon in the EIP1967 beacon slot.\n     */\n    function _setBeacon(address newBeacon) private {\n        if (newBeacon.code.length == 0) {\n            revert ERC1967InvalidBeacon(newBeacon);\n        }\n\n        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;\n\n        address beaconImplementation = IBeacon(newBeacon).implementation();\n        if (beaconImplementation.code.length == 0) {\n            revert ERC1967InvalidImplementation(beaconImplementation);\n        }\n    }\n\n    /**\n     * @dev Change the beacon and trigger a setup call if data is nonempty.\n     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected\n     * to avoid stuck value in the contract.\n     *\n     * Emits an {IERC1967-BeaconUpgraded} event.\n     *\n     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since\n     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for\n     * efficiency.\n     */\n    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {\n        _setBeacon(newBeacon);\n        emit BeaconUpgraded(newBeacon);\n\n        if (data.length > 0) {\n            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n        } else {\n            _checkNonPayable();\n        }\n    }\n\n    /**\n     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract\n     * if an upgrade doesn't perform an initialization call.\n     */\n    function _checkNonPayable() private {\n        if (msg.value > 0) {\n            revert ERC1967NonPayable();\n        }\n    }\n}\n"},"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"@openzeppelin/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"},"@openzeppelin/contracts/utils/Address.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert FailedInnerCall();\n        }\n    }\n}\n"},"@openzeppelin/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Muldiv operation overflow.\n     */\n    error MathOverflowedMulDiv();\n\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            return a / b;\n        }\n\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                revert MathOverflowedMulDiv();\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},"@openzeppelin/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n    /**\n     * @dev Value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedIntToUint(int256 value);\n\n    /**\n     * @dev Value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n    /**\n     * @dev An uint value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedUintToInt(uint256 value);\n\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        if (value > type(uint248).max) {\n            revert SafeCastOverflowedUintDowncast(248, value);\n        }\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        if (value > type(uint240).max) {\n            revert SafeCastOverflowedUintDowncast(240, value);\n        }\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        if (value > type(uint232).max) {\n            revert SafeCastOverflowedUintDowncast(232, value);\n        }\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        if (value > type(uint224).max) {\n            revert SafeCastOverflowedUintDowncast(224, value);\n        }\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        if (value > type(uint216).max) {\n            revert SafeCastOverflowedUintDowncast(216, value);\n        }\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        if (value > type(uint208).max) {\n            revert SafeCastOverflowedUintDowncast(208, value);\n        }\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        if (value > type(uint200).max) {\n            revert SafeCastOverflowedUintDowncast(200, value);\n        }\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        if (value > type(uint192).max) {\n            revert SafeCastOverflowedUintDowncast(192, value);\n        }\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        if (value > type(uint184).max) {\n            revert SafeCastOverflowedUintDowncast(184, value);\n        }\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        if (value > type(uint176).max) {\n            revert SafeCastOverflowedUintDowncast(176, value);\n        }\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        if (value > type(uint168).max) {\n            revert SafeCastOverflowedUintDowncast(168, value);\n        }\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        if (value > type(uint160).max) {\n            revert SafeCastOverflowedUintDowncast(160, value);\n        }\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        if (value > type(uint152).max) {\n            revert SafeCastOverflowedUintDowncast(152, value);\n        }\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        if (value > type(uint144).max) {\n            revert SafeCastOverflowedUintDowncast(144, value);\n        }\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        if (value > type(uint136).max) {\n            revert SafeCastOverflowedUintDowncast(136, value);\n        }\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        if (value > type(uint128).max) {\n            revert SafeCastOverflowedUintDowncast(128, value);\n        }\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        if (value > type(uint120).max) {\n            revert SafeCastOverflowedUintDowncast(120, value);\n        }\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        if (value > type(uint112).max) {\n            revert SafeCastOverflowedUintDowncast(112, value);\n        }\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        if (value > type(uint104).max) {\n            revert SafeCastOverflowedUintDowncast(104, value);\n        }\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        if (value > type(uint96).max) {\n            revert SafeCastOverflowedUintDowncast(96, value);\n        }\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        if (value > type(uint88).max) {\n            revert SafeCastOverflowedUintDowncast(88, value);\n        }\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        if (value > type(uint80).max) {\n            revert SafeCastOverflowedUintDowncast(80, value);\n        }\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        if (value > type(uint72).max) {\n            revert SafeCastOverflowedUintDowncast(72, value);\n        }\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        if (value > type(uint64).max) {\n            revert SafeCastOverflowedUintDowncast(64, value);\n        }\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        if (value > type(uint56).max) {\n            revert SafeCastOverflowedUintDowncast(56, value);\n        }\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        if (value > type(uint48).max) {\n            revert SafeCastOverflowedUintDowncast(48, value);\n        }\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        if (value > type(uint40).max) {\n            revert SafeCastOverflowedUintDowncast(40, value);\n        }\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        if (value > type(uint32).max) {\n            revert SafeCastOverflowedUintDowncast(32, value);\n        }\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        if (value > type(uint24).max) {\n            revert SafeCastOverflowedUintDowncast(24, value);\n        }\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        if (value > type(uint16).max) {\n            revert SafeCastOverflowedUintDowncast(16, value);\n        }\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        if (value > type(uint8).max) {\n            revert SafeCastOverflowedUintDowncast(8, value);\n        }\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        if (value < 0) {\n            revert SafeCastOverflowedIntToUint(value);\n        }\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(248, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(240, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(232, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(224, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(216, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(208, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(200, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(192, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(184, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(176, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(168, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(160, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(152, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(144, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(136, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(128, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(120, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(112, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(104, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(96, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(88, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(80, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(72, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(64, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(56, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(48, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(40, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(32, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(24, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(16, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(8, value);\n        }\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        if (value > uint256(type(int256).max)) {\n            revert SafeCastOverflowedUintToInt(value);\n        }\n        return int256(value);\n    }\n}\n"},"@openzeppelin/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(newImplementation.code.length > 0);\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n}\n"},"contracts/compliance/ComplianceConfigurationService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSComplianceConfigurationService.sol\";\nimport \"../data-stores/ComplianceConfigurationDataStore.sol\";\nimport \"../utils/BaseDSContract.sol\";\n\ncontract ComplianceConfigurationService is IDSComplianceConfigurationService, ComplianceConfigurationDataStore, BaseDSContract {\n\n    function initialize() public override onlyProxy initializer {\n        __BaseDSContract_init();\n    }\n\n    function setCountriesCompliance(string[] calldata _countries, uint256[] calldata _values) public override onlyTransferAgentOrAbove {\n        require(_countries.length <= 35, \"Exceeded the maximum number of countries\");\n        require(_countries.length == _values.length, \"Wrong length of parameters\");\n        for (uint i = 0; i < _countries.length; i++) {\n            setCountryCompliance(_countries[i], _values[i]);\n        }\n    }\n\n    function setCountryCompliance(string calldata _country, uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceStringToUIntMapRuleSet(\"countryCompliance\", _country, countriesCompliances[_country], _value);\n        countriesCompliances[_country] = _value;\n    }\n\n    function getCountryCompliance(string memory _country) public view override returns (uint256) {\n        return countriesCompliances[_country];\n    }\n\n    function getTotalInvestorsLimit() public view override returns (uint256) {\n        return totalInvestorsLimit;\n    }\n\n    function setTotalInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"totalInvestorsLimit\", totalInvestorsLimit, _value);\n        totalInvestorsLimit = _value;\n    }\n\n    function getMinUSTokens() public view override returns (uint256) {\n        return minUSTokens;\n    }\n\n    function setMinUSTokens(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"minUSTokens\", minUSTokens, _value);\n        minUSTokens = _value;\n    }\n\n    function getMinEUTokens() public view override returns (uint256) {\n        return minEUTokens;\n    }\n\n    function setMinEUTokens(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"minEUTokens\", minEUTokens, _value);\n        minEUTokens = _value;\n    }\n\n    function getUSInvestorsLimit() public view override returns (uint256) {\n        return usInvestorsLimit;\n    }\n\n    function setUSInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"usInvestorsLimit\", usInvestorsLimit, _value);\n        usInvestorsLimit = _value;\n    }\n\n    function getJPInvestorsLimit() public view override returns (uint256) {\n        return jpInvestorsLimit;\n    }\n\n    function setJPInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"jpInvestorsLimit\", jpInvestorsLimit, _value);\n        jpInvestorsLimit = _value;\n    }\n\n    function getUSAccreditedInvestorsLimit() public view override returns (uint256) {\n        return usAccreditedInvestorsLimit;\n    }\n\n    function setUSAccreditedInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"usAccreditedInvestorsLimit\", usAccreditedInvestorsLimit, _value);\n        usAccreditedInvestorsLimit = _value;\n    }\n\n    function getNonAccreditedInvestorsLimit() public view override returns (uint256) {\n        return nonAccreditedInvestorsLimit;\n    }\n\n    function setNonAccreditedInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"nonAccreditedInvestorsLimit\", nonAccreditedInvestorsLimit, _value);\n        nonAccreditedInvestorsLimit = _value;\n    }\n\n    function getMaxUSInvestorsPercentage() public view override returns (uint256) {\n        return maxUSInvestorsPercentage;\n    }\n\n    function setMaxUSInvestorsPercentage(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"maxUSInvestorsPercentage\", maxUSInvestorsPercentage, _value);\n        maxUSInvestorsPercentage = _value;\n    }\n\n    function getBlockFlowbackEndTime() public view override returns (uint256) {\n        return blockFlowbackEndTime;\n    }\n\n    function setBlockFlowbackEndTime(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"blockFlowbackEndTime\", blockFlowbackEndTime, _value);\n        blockFlowbackEndTime = _value;\n    }\n\n    function getNonUSLockPeriod() public view override returns (uint256) {\n        return nonUSLockPeriod;\n    }\n\n    function setNonUSLockPeriod(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"nonUSLockPeriod\", nonUSLockPeriod, _value);\n        nonUSLockPeriod = _value;\n    }\n\n    function getMinimumTotalInvestors() public view override returns (uint256) {\n        return minimumTotalInvestors;\n    }\n\n    function setMinimumTotalInvestors(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"minimumTotalInvestors\", minimumTotalInvestors, _value);\n        minimumTotalInvestors = _value;\n    }\n\n    function getMinimumHoldingsPerInvestor() public view override returns (uint256) {\n        return minimumHoldingsPerInvestor;\n    }\n\n    function setMinimumHoldingsPerInvestor(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"minimumHoldingsPerInvestor\", minimumHoldingsPerInvestor, _value);\n        minimumHoldingsPerInvestor = _value;\n    }\n\n    function getMaximumHoldingsPerInvestor() public view override returns (uint256) {\n        return maximumHoldingsPerInvestor;\n    }\n\n    function setMaximumHoldingsPerInvestor(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"maximumHoldingsPerInvestor\", maximumHoldingsPerInvestor, _value);\n        maximumHoldingsPerInvestor = _value;\n    }\n\n    function getEURetailInvestorsLimit() public view override returns (uint256) {\n        return euRetailInvestorsLimit;\n    }\n\n    function setEURetailInvestorsLimit(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"euRetailInvestorsLimit\", euRetailInvestorsLimit, _value);\n        euRetailInvestorsLimit = _value;\n    }\n\n    function getUSLockPeriod() public view override returns (uint256) {\n        return usLockPeriod;\n    }\n\n    function setUSLockPeriod(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"usLockPeriod\", usLockPeriod, _value);\n        usLockPeriod = _value;\n    }\n\n    function getForceFullTransfer() public view override returns (bool) {\n        return forceFullTransfer;\n    }\n\n    function setForceFullTransfer(bool _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceBoolRuleSet(\"forceFullTransfer\", forceFullTransfer, _value);\n        forceFullTransfer = _value;\n    }\n\n    function getForceAccreditedUS() public view override returns (bool) {\n        return forceAccreditedUS;\n    }\n\n    function setForceAccreditedUS(bool _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceBoolRuleSet(\"forceAccreditedUS\", forceAccreditedUS, _value);\n        forceAccreditedUS = _value;\n    }\n\n    function getForceAccredited() public view override returns (bool) {\n        return forceAccredited;\n    }\n\n    function setForceAccredited(bool _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceBoolRuleSet(\"forceAccredited\", forceAccredited, _value);\n        forceAccredited = _value;\n    }\n\n    function getWorldWideForceFullTransfer() public view override returns (bool) {\n        return worldWideForceFullTransfer;\n    }\n\n    function setWorldWideForceFullTransfer(bool _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceBoolRuleSet(\"worldWideForceFullTransfer\", worldWideForceFullTransfer, _value);\n        worldWideForceFullTransfer = _value;\n    }\n\n    function getAuthorizedSecurities() public view override returns (uint256) {\n        return authorizedSecurities;\n    }\n\n    function setAuthorizedSecurities(uint256 _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceUIntRuleSet(\"authorizedSecurities\", authorizedSecurities, _value);\n        authorizedSecurities = _value;\n    }\n\n    function getDisallowBackDating() public view override returns (bool) {\n        return disallowBackDating;\n    }\n\n    function setDisallowBackDating(bool _value) public override onlyTransferAgentOrAbove {\n        emit DSComplianceBoolRuleSet(\"disallowBackDating\", disallowBackDating, _value);\n        disallowBackDating = _value;\n    }\n\n    function setAll(uint256[] calldata _uint_values, bool[] calldata _bool_values) public override onlyTransferAgentOrAbove {\n        require(_uint_values.length == 16, \"Wrong length of parameters\");\n        require(_bool_values.length == 5, \"Wrong length of parameters\");\n        setTotalInvestorsLimit(_uint_values[0]);\n        setMinUSTokens(_uint_values[1]);\n        setMinEUTokens(_uint_values[2]);\n        setUSInvestorsLimit(_uint_values[3]);\n        setUSAccreditedInvestorsLimit(_uint_values[4]);\n        setNonAccreditedInvestorsLimit(_uint_values[5]);\n        setMaxUSInvestorsPercentage(_uint_values[6]);\n        setBlockFlowbackEndTime(_uint_values[7]);\n        setNonUSLockPeriod(_uint_values[8]);\n        setMinimumTotalInvestors(_uint_values[9]);\n        setMinimumHoldingsPerInvestor(_uint_values[10]);\n        setMaximumHoldingsPerInvestor(_uint_values[11]);\n        setEURetailInvestorsLimit(_uint_values[12]);\n        setUSLockPeriod(_uint_values[13]);\n        setJPInvestorsLimit(_uint_values[14]);\n        setAuthorizedSecurities(_uint_values[15]);\n        setForceFullTransfer(_bool_values[0]);\n        setForceAccredited(_bool_values[1]);\n        setForceAccreditedUS(_bool_values[2]);\n        setWorldWideForceFullTransfer(_bool_values[3]);\n        setDisallowBackDating(_bool_values[4]);\n    }\n\n    function getAll() public view override returns (uint256[] memory, bool[] memory) {\n        uint256[] memory uintValues = new uint256[](16);\n        bool[] memory boolValues = new bool[](5);\n\n        uintValues[0] = getTotalInvestorsLimit();\n        uintValues[1] = getMinUSTokens();\n        uintValues[2] = getMinEUTokens();\n        uintValues[3] = getUSInvestorsLimit();\n        uintValues[4] = getUSAccreditedInvestorsLimit();\n        uintValues[5] = getNonAccreditedInvestorsLimit();\n        uintValues[6] = getMaxUSInvestorsPercentage();\n        uintValues[7] = getBlockFlowbackEndTime();\n        uintValues[8] = getNonUSLockPeriod();\n        uintValues[9] = getMinimumTotalInvestors();\n        uintValues[10] = getMinimumHoldingsPerInvestor();\n        uintValues[11] = getMaximumHoldingsPerInvestor();\n        uintValues[12] = getEURetailInvestorsLimit();\n        uintValues[13] = getUSLockPeriod();\n        uintValues[14] = getJPInvestorsLimit();\n        uintValues[15] = getAuthorizedSecurities();\n        boolValues[0] = getForceFullTransfer();\n        boolValues[1] = getForceAccredited();\n        boolValues[2] = getForceAccreditedUS();\n        boolValues[3] = getWorldWideForceFullTransfer();\n        boolValues[4] = getDisallowBackDating();\n        return (uintValues, boolValues);\n    }\n}\n"},"contracts/compliance/ComplianceService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSComplianceService.sol\";\nimport \"../utils/CommonUtils.sol\";\nimport \"../data-stores/ComplianceServiceDataStore.sol\";\nimport \"../utils/BaseDSContract.sol\";\n\n/**\n *   @title Compliance service main implementation.\n *\n *   Combines the different implementation files for the compliance service and serves as a base class for\n *   concrete implementation.\n *\n *   To create a concrete implementation of a compliance service, one should inherit from this contract,\n *   and implement the five functions - recordIssuance,checkTransfer,recordTransfer,recordBurn and recordSeize.\n *   The rest of the functions should only be overridden in rare circumstances.\n */\n\nabstract contract ComplianceService is IDSComplianceService, ComplianceServiceDataStore, BaseDSContract {\n\n    function initialize() public virtual override onlyProxy onlyInitializing {\n        __BaseDSContract_init();\n    }\n\n    function validateTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public override onlyToken returns (bool) {\n        uint256 code;\n        string memory reason;\n\n        (code, reason) = preTransferCheck(_from, _to, _value);\n        require(code == 0, reason);\n\n        return recordTransfer(_from, _to, _value);\n    }\n\n    function validateTransfer(\n        address _from,\n        address _to,\n        uint256 _value,\n        bool _paused,\n        uint256 _balanceFrom\n    ) public virtual override onlyToken returns (bool) {\n        uint256 code;\n        string memory reason;\n\n        (code, reason) = newPreTransferCheck(_from, _to, _value, _balanceFrom, _paused);\n        require(code == 0, reason);\n\n        return recordTransfer(_from, _to, _value);\n    }\n\n    function validateIssuance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) public override onlyToken returns (bool) {\n        uint256 code;\n        string memory reason;\n\n        uint256 authorizedSecurities = getComplianceConfigurationService().getAuthorizedSecurities();\n\n        require(authorizedSecurities == 0 || getToken().totalSupply() + _value <= authorizedSecurities,\n            MAX_AUTHORIZED_SECURITIES_EXCEEDED);\n\n        (code, reason) = preIssuanceCheck(_to, _value);\n        require(code == 0, reason);\n\n        uint256 issuanceTime = validateIssuanceTime(_issuanceTime);\n        return recordIssuance(_to, _value, issuanceTime);\n    }\n\n    function validateIssuanceWithNoCompliance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) public override onlyToken returns (bool) {\n        uint256 authorizedSecurities = getComplianceConfigurationService().getAuthorizedSecurities();\n\n        require(authorizedSecurities == 0 || getToken().totalSupply() + _value <= authorizedSecurities,\n            MAX_AUTHORIZED_SECURITIES_EXCEEDED);\n\n        uint256 issuanceTime = validateIssuanceTime(_issuanceTime);\n        return recordIssuance(_to, _value, issuanceTime);\n    }\n\n    function validateBurn(address _who, uint256 _value) public virtual override onlyToken returns (bool) {\n        return recordBurn(_who, _value);\n    }\n\n    function validateSeize(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public virtual override onlyToken returns (bool) {\n        require(getWalletManager().isIssuerSpecialWallet(_to), \"Target wallet type error\");\n\n        return recordSeize(_from, _to, _value);\n    }\n\n    /**\n     * @dev Verify disallowBackDating compliance: if set to false returns _issuanceTime parameter, otherwise returns current timestamp\n     * @param _issuanceTime.\n     * @return issuanceTime\n     */\n    function validateIssuanceTime(uint256 _issuanceTime) public view override returns (uint256 issuanceTime) {\n        if (!getComplianceConfigurationService().getDisallowBackDating()) {\n            return _issuanceTime;\n        }\n        return block.timestamp;\n    }\n\n    function newPreTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _pausedToken\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        if (_pausedToken) {\n            return (10, TOKEN_PAUSED);\n        }\n\n        if (_balanceFrom < _value) {\n            return (15, NOT_ENOUGH_TOKENS);\n        }\n\n        if (getLockManager().getTransferableTokens(_from, block.timestamp) < _value) {\n            return (16, TOKENS_LOCKED);\n        }\n\n        return checkTransfer(_from, _to, _value);\n    }\n\n    function preTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        if (getToken().isPaused()) {\n            return (10, TOKEN_PAUSED);\n        }\n\n        if (getToken().balanceOf(_from) < _value) {\n            return (15, NOT_ENOUGH_TOKENS);\n        }\n\n        if (getLockManager().getTransferableTokens(_from, block.timestamp) < _value) {\n            return (16, TOKENS_LOCKED);\n        }\n\n        return checkTransfer(_from, _to, _value);\n    }\n\n    function preInternalTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        if (getToken().isPaused()) {\n            return (10, TOKEN_PAUSED);\n        }\n\n        return checkTransfer(_from, _to, _value);\n    }\n\n    function preIssuanceCheck(\n        address, /*_to*/\n        uint256 /*_value*/\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        return (0, VALID);\n    }\n\n    function adjustInvestorCountsAfterCountryChange(\n        string memory, /*_id*/\n        string memory, /*_country*/\n        string memory /*_prevCountry*/\n    ) public virtual override returns (bool) {\n        return true;\n    }\n\n    // These functions should be implemented by the concrete compliance manager\n    function recordIssuance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) internal virtual returns (bool);\n\n    function recordTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal virtual returns (bool);\n\n    function recordBurn(address _who, uint256 _value) internal virtual returns (bool);\n\n    function recordSeize(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal virtual returns (bool);\n\n    function checkTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal view virtual returns (uint256, string memory);\n}\n"},"contracts/compliance/ComplianceServiceRegulated.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ComplianceServiceWhitelisted.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nlibrary ComplianceServiceLibrary {\n    uint256 internal constant DS_TOKEN = 0;\n    uint256 internal constant REGISTRY_SERVICE = 1;\n    uint256 internal constant WALLET_MANAGER = 2;\n    uint256 internal constant COMPLIANCE_CONFIGURATION_SERVICE = 3;\n    uint256 internal constant LOCK_MANAGER = 4;\n    uint256 internal constant COMPLIANCE_SERVICE = 5;\n    uint256 internal constant OMNIBUS_TBE_CONTROLLER = 6;\n    uint256 internal constant NONE = 0;\n    uint256 internal constant US = 1;\n    uint256 internal constant EU = 2;\n    uint256 internal constant FORBIDDEN = 4;\n    uint256 internal constant JP = 8;\n    string internal constant TOKEN_PAUSED = \"Token paused\";\n    string internal constant NOT_ENOUGH_TOKENS = \"Not enough tokens\";\n    string internal constant VALID = \"Valid\";\n    string internal constant TOKENS_LOCKED = \"Tokens locked\";\n    string internal constant ONLY_FULL_TRANSFER = \"Only full transfer\";\n    string internal constant FLOWBACK = \"Flowback\";\n    string internal constant WALLET_NOT_IN_REGISTRY_SERVICE = \"Wallet not in registry service\";\n    string internal constant AMOUNT_OF_TOKENS_UNDER_MIN = \"Amount of tokens under min\";\n    string internal constant AMOUNT_OF_TOKENS_ABOVE_MAX = \"Amount of tokens above max\";\n    string internal constant HOLD_UP = \"Under lock-up\";\n    string internal constant DESTINATION_RESTRICTED = \"Destination restricted\";\n    string internal constant MAX_INVESTORS_IN_CATEGORY = \"Max investors in category\";\n    string internal constant ONLY_ACCREDITED = \"Only accredited\";\n    string internal constant ONLY_US_ACCREDITED = \"Only us accredited\";\n    string internal constant NOT_ENOUGH_INVESTORS = \"Not enough investors\";\n\n    struct CompletePreTransferCheckArgs {\n        address from;\n        address to;\n        uint256 value;\n        uint256 fromInvestorBalance;\n        uint256 fromRegion;\n        bool isPlatformWalletTo;\n    }\n\n    function isRetail(address[] memory _services, address _wallet) internal view returns (bool) {\n        IDSRegistryService registry = IDSRegistryService(_services[REGISTRY_SERVICE]);\n\n        return !registry.isQualifiedInvestor(_wallet);\n    }\n\n    function isAccredited(address[] memory _services, address _wallet) internal view returns (bool) {\n        IDSRegistryService registry = IDSRegistryService(_services[REGISTRY_SERVICE]);\n\n        return registry.isAccreditedInvestor(_wallet);\n    }\n\n    function balanceOfInvestor(address[] memory _services, address _wallet) internal view returns (uint256) {\n        IDSRegistryService registry = IDSRegistryService(_services[REGISTRY_SERVICE]);\n        IDSToken token = IDSToken(_services[DS_TOKEN]);\n\n        return token.balanceOfInvestor(registry.getInvestor(_wallet));\n    }\n\n    function isNewInvestor(address[] memory _services, address _to, uint256 _balanceOfInvestorTo) internal view returns (bool) {\n        IDSOmnibusTBEController omnibusTBEController = IDSOmnibusTBEController(_services[OMNIBUS_TBE_CONTROLLER]);\n\n        // Return whether this investor has 0 balance and is not an omnibus TBE wallet\n        return _balanceOfInvestorTo == 0 && !isOmnibusTBE(omnibusTBEController, _to);\n    }\n\n    function getCountry(address[] memory _services, address _wallet) internal view returns (string memory) {\n        IDSRegistryService registry = IDSRegistryService(_services[REGISTRY_SERVICE]);\n\n        return registry.getCountry(registry.getInvestor(_wallet));\n    }\n\n    function getCountryCompliance(address[] memory _services, address _wallet) internal view returns (uint256) {\n        return IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getCountryCompliance(getCountry(_services, _wallet));\n    }\n\n    function getUSInvestorsLimit(address[] memory _services) internal view returns (uint256) {\n        ComplianceServiceRegulated complianceService = ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]);\n        IDSComplianceConfigurationService compConfService = IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]);\n\n        if (compConfService.getMaxUSInvestorsPercentage() == 0) {\n            return compConfService.getUSInvestorsLimit();\n        }\n\n        if (compConfService.getUSInvestorsLimit() == 0) {\n            return compConfService.getMaxUSInvestorsPercentage() * (complianceService.getTotalInvestorsCount()) / 100;\n        }\n\n        return Math.min(compConfService.getUSInvestorsLimit(), compConfService.getMaxUSInvestorsPercentage() * (complianceService.getTotalInvestorsCount()) / 100);\n    }\n\n    function isOmnibusTBE(IDSOmnibusTBEController _omnibusTBE, address _from) internal view returns (bool) {\n        if (address(_omnibusTBE) != address(0)) {\n            return _omnibusTBE.getOmnibusWallet() == _from;\n        }\n        return false;\n    }\n\n    function checkHoldUp(\n        address[] memory _services,\n        address _from,\n        uint256 _value,\n        bool _isUSLockPeriod,\n        bool _isPlatformWalletFrom\n    ) internal view returns (bool) {\n        ComplianceServiceRegulated complianceService = ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]);\n        uint256 lockPeriod;\n        if (_isUSLockPeriod) {\n            lockPeriod = IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getUSLockPeriod();\n        } else {\n            lockPeriod = IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getNonUSLockPeriod();\n        }\n\n        return\n        !_isPlatformWalletFrom &&\n        complianceService.getComplianceTransferableTokens(_from, block.timestamp, uint64(lockPeriod)) < _value;\n    }\n\n    function maxInvestorsInCategoryForNonAccredited(\n        address[] memory _services,\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 fromInvestorBalance,\n        uint256 toInvestorBalance\n    ) internal view returns (bool) {\n        uint256 nonAccreditedInvestorLimit = IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getNonAccreditedInvestorsLimit();\n        return\n        nonAccreditedInvestorLimit != 0 &&\n        ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getTotalInvestorsCount() -\n            ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getAccreditedInvestorsCount()\n        >=\n        nonAccreditedInvestorLimit &&\n        isNewInvestor(_services, _to, toInvestorBalance) &&\n        (isAccredited(_services, _from) || fromInvestorBalance > _value);\n    }\n\n    function newPreTransferCheck(\n        address[] calldata _services,\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _paused\n    ) public view returns (uint256 code, string memory reason) {\n        return doPreTransferCheckRegulated\n        (_services, _from, _to, _value, _balanceFrom, _paused);\n    }\n\n    function preTransferCheck(\n        address[] calldata _services,\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view returns (uint256 code, string memory reason) {\n        return doPreTransferCheckRegulated(_services, _from, _to, _value, IDSToken(_services[DS_TOKEN]).balanceOf(_from), IDSToken(_services[DS_TOKEN]).isPaused());\n    }\n\n    function doPreTransferCheckRegulated(\n        address[] memory _services,\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _paused\n    ) internal view returns (uint256 code, string memory reason) {\n\n        if (_balanceFrom < _value) {\n            return (15, NOT_ENOUGH_TOKENS);\n        }\n\n        uint256 fromInvestorBalance = balanceOfInvestor(_services, _from);\n        uint256 fromRegion = getCountryCompliance(_services, _from);\n        bool isPlatformWalletTo = IDSWalletManager(_services[WALLET_MANAGER]).isPlatformWallet(_to);\n        if (isPlatformWalletTo) {\n            if (\n                ((IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getForceFullTransfer()\n                && (fromRegion == US)) ||\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getWorldWideForceFullTransfer()) &&\n                fromInvestorBalance > _value\n            ) {\n                return (50, ONLY_FULL_TRANSFER);\n            }\n            return (0, VALID);\n        }\n\n        if (_paused && !(isOmnibusTBE(IDSOmnibusTBEController(_services[OMNIBUS_TBE_CONTROLLER]), _from))) {\n            return (10, TOKEN_PAUSED);\n        }\n\n        CompletePreTransferCheckArgs memory args = CompletePreTransferCheckArgs(_from, _to, _value, fromInvestorBalance, fromRegion, isPlatformWalletTo);\n        return completeTransferCheck(_services, args);\n    }\n\n    function completeTransferCheck(\n        address[] memory _services,\n        CompletePreTransferCheckArgs memory _args\n    ) internal view returns (uint256 code, string memory reason) {\n        (string memory investorFrom, string memory investorTo) = IDSRegistryService(_services[REGISTRY_SERVICE]).getInvestors(_args.from, _args.to);\n        if (\n            !CommonUtils.isEmptyString(investorFrom) && CommonUtils.isEqualString(investorFrom, investorTo)\n        ) {\n            return (0, VALID);\n        }\n\n        if (!ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).checkWhitelisted(_args.to)) {\n            return (20, WALLET_NOT_IN_REGISTRY_SERVICE);\n        }\n\n        uint256 toRegion = getCountryCompliance(_services, _args.to);\n        if (toRegion == FORBIDDEN) {\n            return (26, DESTINATION_RESTRICTED);\n        }\n\n        if (isOmnibusTBE(IDSOmnibusTBEController(_services[OMNIBUS_TBE_CONTROLLER]), _args.from)) {\n            return(0, VALID);\n        }\n\n        bool isPlatformWalletFrom = IDSWalletManager(_services[WALLET_MANAGER]).isPlatformWallet(_args.from);\n        if (\n            !isPlatformWalletFrom &&\n        IDSLockManager(_services[LOCK_MANAGER]).getTransferableTokens(_args.from, block.timestamp) < _args.value\n        ) {\n            return (16, TOKENS_LOCKED);\n        }\n\n        if (_args.fromRegion == US) {\n            if (checkHoldUp(_services, _args.from, _args.value, true, isPlatformWalletFrom)) {\n                return (32, HOLD_UP);\n            }\n\n            if (\n                _args.fromInvestorBalance > _args.value &&\n                _args.fromInvestorBalance - _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinUSTokens()\n            ) {\n                return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n            }\n\n            if (\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getForceFullTransfer() &&\n                _args.fromInvestorBalance > _args.value\n            ) {\n                return (50, ONLY_FULL_TRANSFER);\n            }\n        } else {\n            if (checkHoldUp(_services, _args.from, _args.value, false, isPlatformWalletFrom)) {\n                return (33, HOLD_UP);\n            }\n\n            if (\n                toRegion == US &&\n                !isPlatformWalletFrom &&\n                isBlockFlowbackEndTimeOk(IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getBlockFlowbackEndTime())\n            ) {\n                return (25, FLOWBACK);\n            }\n\n            if (\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getWorldWideForceFullTransfer() &&\n                _args.fromInvestorBalance > _args.value\n            ) {\n                return (50, ONLY_FULL_TRANSFER);\n            }\n        }\n\n        uint256 toInvestorBalance = balanceOfInvestor(_services, _args.to);\n        string memory toCountry = getCountry(_services, _args.to);\n\n        if (_args.fromRegion == EU) {\n            if (_args.fromInvestorBalance - _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinEUTokens() &&\n                _args.fromInvestorBalance > _args.value) {\n                return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n            }\n        }\n\n        bool isAccreditedTo = isAccredited(_services, _args.to);\n        if (\n            IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getForceAccredited() && !isAccreditedTo\n        ) {\n            return (61, ONLY_ACCREDITED);\n        }\n\n        if (toRegion == JP) {\n            if (\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getJPInvestorsLimit() != 0 &&\n                ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getJPInvestorsCount() >=\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getJPInvestorsLimit() &&\n                isNewInvestor(_services, _args.to, toInvestorBalance) &&\n                (!CommonUtils.isEqualString(getCountry(_services, _args.from), toCountry) || (_args.fromInvestorBalance > _args.value))\n            ) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n        } else if (toRegion == EU) {\n            if (\n                isRetail(_services, _args.to) &&\n                ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getEURetailInvestorsCount(toCountry) >=\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getEURetailInvestorsLimit() &&\n                isNewInvestor(_services, _args.to, toInvestorBalance) &&\n                (!CommonUtils.isEqualString(getCountry(_services, _args.from), toCountry) ||\n                (_args.fromInvestorBalance > _args.value && isRetail(_services, _args.from)))\n            ) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n\n            if (\n                toInvestorBalance + _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinEUTokens()\n            ) {\n                return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n            }\n        } else if (toRegion == US) {\n            if (\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getForceAccreditedUS() &&\n                !isAccreditedTo\n            ) {\n                return (62, ONLY_US_ACCREDITED);\n            }\n\n            uint256 usInvestorsLimit = getUSInvestorsLimit(_services);\n            if (\n                usInvestorsLimit != 0 &&\n                _args.fromInvestorBalance > _args.value &&\n                ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getUSInvestorsCount() >= usInvestorsLimit &&\n                isNewInvestor(_services, _args.to, toInvestorBalance)\n            ) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n\n            if (\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getUSAccreditedInvestorsLimit() != 0 &&\n                isAccreditedTo &&\n                ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getUSAccreditedInvestorsCount() >=\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getUSAccreditedInvestorsLimit() &&\n                isNewInvestor(_services, _args.to, toInvestorBalance) &&\n                (_args.fromRegion != US || !isAccredited(_services, _args.from) || _args.fromInvestorBalance > _args.value)\n            ) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n\n            if (\n                toInvestorBalance + _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinUSTokens()\n            ) {\n                return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n            }\n        }\n\n        if (!isAccreditedTo) {\n            if (maxInvestorsInCategoryForNonAccredited(_services, _args.from, _args.to, _args.value, _args.fromInvestorBalance, toInvestorBalance)) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n        }\n\n        if (\n            IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getTotalInvestorsLimit() != 0 &&\n            _args.fromInvestorBalance > _args.value &&\n            ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getTotalInvestorsCount() >=\n            IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getTotalInvestorsLimit() &&\n            isNewInvestor(_services, _args.to, toInvestorBalance)\n        ) {\n            return (40, MAX_INVESTORS_IN_CATEGORY);\n        }\n\n        if (\n            _args.fromInvestorBalance == _args.value &&\n            !isNewInvestor(_services, _args.to, toInvestorBalance) &&\n            ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]).getTotalInvestorsCount() <=\n            IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinimumTotalInvestors()\n        ) {\n            return (71, NOT_ENOUGH_INVESTORS);\n        }\n\n        if (\n            !isPlatformWalletFrom &&\n        _args.fromInvestorBalance - _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinimumHoldingsPerInvestor() &&\n        _args.fromInvestorBalance > _args.value\n        ) {\n            return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n        }\n\n        if (\n            !_args.isPlatformWalletTo &&\n        toInvestorBalance + _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinimumHoldingsPerInvestor()\n        ) {\n            return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n        }\n\n        if (\n            isMaximumHoldingsPerInvestorOk(\n                IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMaximumHoldingsPerInvestor(),\n                toInvestorBalance, _args.value)\n        ) {\n            return (52, AMOUNT_OF_TOKENS_ABOVE_MAX);\n        }\n\n        return (0, VALID);\n    }\n\n\n    function preIssuanceCheck(\n        address[] calldata _services,\n        address _to,\n        uint256 _value\n    ) public view returns (uint256 code, string memory reason) {\n        ComplianceServiceRegulated complianceService = ComplianceServiceRegulated(_services[COMPLIANCE_SERVICE]);\n        IDSComplianceConfigurationService complianceConfigurationService = IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]);\n        IDSWalletManager walletManager = IDSWalletManager(_services[WALLET_MANAGER]);\n        string memory toCountry = IDSRegistryService(_services[REGISTRY_SERVICE]).getCountry(IDSRegistryService(_services[REGISTRY_SERVICE]).getInvestor(_to));\n        uint256 toRegion = complianceConfigurationService.getCountryCompliance(toCountry);\n\n        if (toRegion == FORBIDDEN) {\n            return (26, DESTINATION_RESTRICTED);\n        }\n\n        if (!complianceService.checkWhitelisted(_to)) {\n            return (20, WALLET_NOT_IN_REGISTRY_SERVICE);\n        }\n\n        uint256 balanceOfInvestorTo = balanceOfInvestor(_services, _to);\n        if (isNewInvestor(_services, _to, balanceOfInvestorTo)) {\n            // verify global non accredited limit\n            if (!isAccredited(_services, _to)) {\n                if (\n                    complianceConfigurationService.getNonAccreditedInvestorsLimit() != 0 &&\n                    complianceService.getTotalInvestorsCount() - complianceService.getAccreditedInvestorsCount() >=\n                    complianceConfigurationService.getNonAccreditedInvestorsLimit()\n                ) {\n                    return (40, MAX_INVESTORS_IN_CATEGORY);\n                }\n            }\n            // verify global investors limit\n            if (\n                complianceConfigurationService.getTotalInvestorsLimit() != 0 &&\n                complianceService.getTotalInvestorsCount() >= complianceConfigurationService.getTotalInvestorsLimit()\n            ) {\n                return (40, MAX_INVESTORS_IN_CATEGORY);\n            }\n\n            if (toRegion == US) {\n                // verify US investors limit is not exceeded\n                if (complianceConfigurationService.getUSInvestorsLimit() != 0 && complianceService.getUSInvestorsCount() >= complianceConfigurationService.getUSInvestorsLimit()) {\n                    return (40, MAX_INVESTORS_IN_CATEGORY);\n                }\n                // verify accredited US limit is not exceeded\n                if (\n                    complianceConfigurationService.getUSAccreditedInvestorsLimit() != 0 &&\n                    isAccredited(_services, _to) &&\n                    complianceService.getUSAccreditedInvestorsCount() >= complianceConfigurationService.getUSAccreditedInvestorsLimit()\n                ) {\n                    return (40, MAX_INVESTORS_IN_CATEGORY);\n                }\n            } else if (toRegion == EU) {\n                if (\n                    isRetail(_services, _to) &&\n                    complianceService.getEURetailInvestorsCount(getCountry(_services, _to)) >= complianceConfigurationService.getEURetailInvestorsLimit()\n                ) {\n                    return (40, MAX_INVESTORS_IN_CATEGORY);\n                }\n            } else if (toRegion == JP) {\n                if (complianceConfigurationService.getJPInvestorsLimit() != 0 && complianceService.getJPInvestorsCount() >= complianceConfigurationService.getJPInvestorsLimit()) {\n                    return (40, MAX_INVESTORS_IN_CATEGORY);\n                }\n            }\n        }\n\n        if (\n            !walletManager.isPlatformWallet(_to) &&\n        balanceOfInvestorTo + _value < complianceConfigurationService.getMinimumHoldingsPerInvestor()\n        ) {\n            return (51, AMOUNT_OF_TOKENS_UNDER_MIN);\n        }\n        if (isMaximumHoldingsPerInvestorOk(\n                complianceConfigurationService.getMaximumHoldingsPerInvestor(),\n                balanceOfInvestorTo,\n                _value)\n        ) {\n            return (52, AMOUNT_OF_TOKENS_ABOVE_MAX);\n        }\n\n        return (0, VALID);\n    }\n\n    function isMaximumHoldingsPerInvestorOk(uint256 _maximumHoldingsPerInvestor, uint256 _balanceOfInvestorTo, uint256 _value) internal pure returns (bool) {\n        return _maximumHoldingsPerInvestor != 0 && _balanceOfInvestorTo + _value > _maximumHoldingsPerInvestor;\n    }\n\n    function isBlockFlowbackEndTimeOk(uint256 _blockFlowBackEndTime) private view returns (bool){\n        return  (_blockFlowBackEndTime == 0 || _blockFlowBackEndTime > block.timestamp);\n    }\n}\n\n/**\n *   @title Concrete compliance service for tokens with regulation\n *\n */\n\ncontract ComplianceServiceRegulated is ComplianceServiceWhitelisted {\n\n    function initialize() public virtual override onlyProxy initializer {\n        super.initialize();\n    }\n\n    function compareInvestorBalance(\n        address _who,\n        uint256 _value,\n        uint256 _compareTo\n    ) internal view returns (bool) {\n        return (_value != 0 && getToken().balanceOfInvestor(getRegistryService().getInvestor(_who)) == _compareTo);\n    }\n\n    function recordTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal override returns (bool) {\n        if (!(ComplianceServiceLibrary.isOmnibusTBE(getOmnibusTBEController(), _from) ||\n        ComplianceServiceLibrary.isOmnibusTBE(getOmnibusTBEController(), _to))) {\n            if (compareInvestorBalance(_to, _value, 0)) {\n                adjustTransferCounts(_to, CommonUtils.IncDec.Increase);\n            }\n        }\n\n        return true;\n    }\n\n    function adjustTransferCounts(\n        address _from,\n        CommonUtils.IncDec _increase\n    ) internal {\n        adjustTotalInvestorsCounts(_from, _increase);\n    }\n\n    function recordIssuance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) internal override returns (bool) {\n        if (compareInvestorBalance(_to, _value, 0)) {\n            adjustTotalInvestorsCounts(_to, CommonUtils.IncDec.Increase);\n        }\n\n        return createIssuanceInformation(getRegistryService().getInvestor(_to), _value, _issuanceTime);\n    }\n\n    function recordBurn(address /*_who*/, uint256 /*_value*/) internal pure override returns (bool) {\n        return true;\n    }\n\n    function recordSeize(\n        address _from,\n        address, /*_to*/\n        uint256 _value\n    ) internal pure override returns (bool) {\n        return recordBurn(_from, _value);\n    }\n\n    function adjustInvestorCountsAfterCountryChange(\n        string memory _id,\n        string memory _country,\n        string memory /*_prevCountry*/\n    ) public override onlyRegistry returns (bool) {\n        if (getToken().balanceOfInvestor(_id) == 0) {\n            return false;\n        }\n\n        adjustInvestorsCountsByCountry(_country, _id, CommonUtils.IncDec.Increase);\n\n        return true;\n    }\n\n    function adjustTotalInvestorsCounts(address _wallet, CommonUtils.IncDec _increase) internal {\n        if (!getWalletManager().isSpecialWallet(_wallet)) {\n            if (_increase == CommonUtils.IncDec.Increase) {\n                totalInvestors++;\n            }\n\n            string memory id = getRegistryService().getInvestor(_wallet);\n            string memory country = getRegistryService().getCountry(id);\n\n            adjustInvestorsCountsByCountry(country, id, _increase);\n        }\n    }\n\n    function adjustInvestorsCountsByCountry(\n        string memory _country,\n        string memory _id,\n        CommonUtils.IncDec _increase\n    ) internal {\n        uint256 countryCompliance = getComplianceConfigurationService().getCountryCompliance(_country);\n\n        if (getRegistryService().isAccreditedInvestor(_id)) {\n            if(_increase == CommonUtils.IncDec.Increase) {\n                accreditedInvestorsCount++;\n            }\n            if (countryCompliance == US) {\n                if(_increase == CommonUtils.IncDec.Increase) {\n                    usAccreditedInvestorsCount++;\n                }\n            }\n        }\n\n        if (countryCompliance == US) {\n            if(_increase == CommonUtils.IncDec.Increase) {\n                usInvestorsCount++;\n            }\n        } else if (countryCompliance == EU && !getRegistryService().isQualifiedInvestor(_id)) {\n            if(_increase == CommonUtils.IncDec.Increase) {\n                euRetailInvestorsCount[_country]++;\n            }\n        } else if (countryCompliance == JP) {\n            if(_increase == CommonUtils.IncDec.Increase) {\n                jpInvestorsCount++;\n            }\n        }\n    }\n\n    function createIssuanceInformation(\n        string memory _investor,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) internal returns (bool) {\n        uint256 issuancesCount = issuancesCounters[_investor];\n\n        issuancesValues[_investor][issuancesCount] = _value;\n        issuancesTimestamps[_investor][issuancesCount] = _issuanceTime;\n        issuancesCounters[_investor] = issuancesCount + 1;\n\n        return true;\n    }\n\n    function preTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        return ComplianceServiceLibrary.preTransferCheck(getServices(), _from, _to, _value);\n    }\n\n    function newPreTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _pausedToken\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        return ComplianceServiceLibrary.newPreTransferCheck(getServices(), _from, _to, _value, _balanceFrom, _pausedToken);\n    }\n\n    function preInternalTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value)\n    public view override returns (uint256 code, string memory reason) {\n        return ComplianceServiceLibrary.preTransferCheck(getServices(), _from, _to, _value);\n    }\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        uint64 _lockTime\n    ) public view override returns (uint256) {\n        require(_time != 0, \"Time must be greater than zero\");\n        string memory investor = getRegistryService().getInvestor(_who);\n\n        uint256 balanceOfInvestor = getLockManager().getTransferableTokens(_who, _time);\n\n        uint256 investorIssuancesCount = issuancesCounters[investor];\n\n        //No locks, go to base class implementation\n        if (investorIssuancesCount == 0) {\n            return balanceOfInvestor;\n        }\n\n        uint256 totalLockedTokens = 0;\n        for (uint256 i = 0; i < investorIssuancesCount; i++) {\n            uint256 issuanceTimestamp = issuancesTimestamps[investor][i];\n\n            if (uint256(_lockTime) > _time || issuanceTimestamp > (_time - uint256(_lockTime))) {\n                totalLockedTokens = totalLockedTokens + issuancesValues[investor][i];\n            }\n        }\n\n        //there may be more locked tokens than actual tokens, so the minimum between the two\n        uint256 transferable = balanceOfInvestor - Math.min(totalLockedTokens, balanceOfInvestor);\n\n        return transferable;\n    }\n\n    function preIssuanceCheck(address _to, uint256 _value) public view override returns (uint256 code, string memory reason) {\n        return ComplianceServiceLibrary.preIssuanceCheck(getServices(), _to, _value);\n    }\n\n    function getTotalInvestorsCount() public view returns (uint256) {\n        return totalInvestors;\n    }\n\n    function getUSInvestorsCount() public view returns (uint256) {\n        return usInvestorsCount;\n    }\n\n    function getUSAccreditedInvestorsCount() public view returns (uint256) {\n        return usAccreditedInvestorsCount;\n    }\n\n    function getAccreditedInvestorsCount() public view returns (uint256) {\n        return accreditedInvestorsCount;\n    }\n\n    function getEURetailInvestorsCount(string calldata _country) public view returns (uint256) {\n        return euRetailInvestorsCount[_country];\n    }\n\n    function getJPInvestorsCount() public view returns (uint256) {\n        return jpInvestorsCount;\n    }\n\n    function setTotalInvestorsCount(uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        totalInvestors = _value;\n\n        return true;\n    }\n\n    function setUSInvestorsCount(uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        usInvestorsCount = _value;\n\n        return true;\n    }\n\n    function setUSAccreditedInvestorsCount(uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        usAccreditedInvestorsCount = _value;\n\n        return true;\n    }\n\n    function setAccreditedInvestorsCount(uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        accreditedInvestorsCount = _value;\n\n        return true;\n    }\n\n    function setEURetailInvestorsCount(string calldata _country, uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        euRetailInvestorsCount[_country] = _value;\n\n        return true;\n    }\n\n    function setJPInvestorsCount(uint256 _value) public onlyMasterOrTBEOmnibus returns (bool) {\n        jpInvestorsCount = _value;\n\n        return true;\n    }\n\n    function getServices() internal view returns (address[] memory services) {\n        services = new address[](7);\n        services[0] = getDSService(DS_TOKEN);\n        services[1] = getDSService(REGISTRY_SERVICE);\n        services[2] = getDSService(WALLET_MANAGER);\n        services[3] = getDSService(COMPLIANCE_CONFIGURATION_SERVICE);\n        services[4] = getDSService(LOCK_MANAGER);\n        services[5] = address(this);\n        services[6] = getDSService(OMNIBUS_TBE_CONTROLLER);\n    }\n}\n"},"contracts/compliance/ComplianceServiceWhitelisted.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ComplianceService.sol\";\n\n/**\n*   @title Concrete compliance service for tokens with whitelisted wallets.\n*\n*   This simple compliance service is meant to be used for tokens that only need to be validated against an investor registry.\n*/\n\ncontract ComplianceServiceWhitelisted is ComplianceService {\n\n    function initialize() public virtual override onlyProxy initializer {\n        ComplianceService.initialize();\n    }\n\n    function newPreTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _pausedToken\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        return doPreTransferCheckWhitelisted(_from, _to, _value, _balanceFrom, _pausedToken);\n    }\n\n    function preTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual override returns (uint256 code, string memory reason) {\n        return doPreTransferCheckWhitelisted(_from, _to, _value, getToken().balanceOf(_from), getToken().isPaused());\n    }\n\n    function checkWhitelisted(address _who) public view returns (bool) {\n        return getWalletManager().isPlatformWallet(_who) || !CommonUtils.isEmptyString(getRegistryService().getInvestor(_who));\n    }\n\n    function recordIssuance(address, uint256, uint256) internal virtual override returns (bool) {\n        return true;\n    }\n\n    function recordTransfer(address, address, uint256) internal virtual override returns (bool) {\n        return true;\n    }\n\n    function checkTransfer(address, address _to, uint256) internal view override returns (uint256, string memory) {\n        if (!checkWhitelisted(_to)) {\n            return (20, WALLET_NOT_IN_REGISTRY_SERVICE);\n        }\n\n        return (0, VALID);\n    }\n\n    function preIssuanceCheck(address _to, uint256) public view virtual override returns (uint256, string memory) {\n        if (!checkWhitelisted(_to)) {\n            return (20, WALLET_NOT_IN_REGISTRY_SERVICE);\n        }\n\n        return (0, VALID);\n    }\n\n    function recordBurn(address, uint256) internal virtual override returns (bool) {\n        return true;\n    }\n\n    function recordSeize(address, address, uint256) internal virtual override returns (bool) {\n        return true;\n    }\n\n    function doPreTransferCheckWhitelisted(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _pausedToken\n    ) internal view returns (uint256 code, string memory reason) {\n        if (_pausedToken) {\n            return (10, TOKEN_PAUSED);\n        }\n\n        if (_balanceFrom < _value) {\n            return (15, NOT_ENOUGH_TOKENS);\n        }\n\n        if (!getWalletManager().isPlatformWallet(_from) && getLockManager().getTransferableTokens(_from, block.timestamp) < _value) {\n            return (16, TOKENS_LOCKED);\n        }\n\n        return checkTransfer(_from, _to, _value);\n    }\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        uint64 /*_lockTime*/\n    ) public view virtual override returns (uint256) {\n        require(_time > 0, \"Time must be greater than zero\");\n        return getLockManager().getTransferableTokens(_who, _time);\n    }\n}\n"},"contracts/compliance/IDSComplianceConfigurationService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSComplianceConfigurationService {\n\n    function initialize() public virtual;\n\n    event DSComplianceUIntRuleSet(string ruleName, uint256 prevValue, uint256 newValue);\n    event DSComplianceBoolRuleSet(string ruleName, bool prevValue, bool newValue);\n    event DSComplianceStringToUIntMapRuleSet(string ruleName, string keyValue, uint256 prevValue, uint256 newValue);\n\n    function getCountryCompliance(string memory _country) public view virtual returns (uint256);\n\n    function setCountriesCompliance(string[] calldata _countries, uint256[] calldata _values) public virtual;\n\n    function setCountryCompliance(\n        string calldata _country,\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getTotalInvestorsLimit() public view virtual returns (uint256);\n\n    function setTotalInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMinUSTokens() public view virtual returns (uint256);\n\n    function setMinUSTokens(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMinEUTokens() public view virtual returns (uint256);\n\n    function setMinEUTokens(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getUSInvestorsLimit() public view virtual returns (uint256);\n\n    function setUSInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getJPInvestorsLimit() public view virtual returns (uint256);\n\n    function setJPInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getUSAccreditedInvestorsLimit() public view virtual returns (uint256);\n\n    function setUSAccreditedInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getNonAccreditedInvestorsLimit() public view virtual returns (uint256);\n\n    function setNonAccreditedInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMaxUSInvestorsPercentage() public view virtual returns (uint256);\n\n    function setMaxUSInvestorsPercentage(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getBlockFlowbackEndTime() public view virtual returns (uint256);\n\n    function setBlockFlowbackEndTime(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getNonUSLockPeriod() public view virtual returns (uint256);\n\n    function setNonUSLockPeriod(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMinimumTotalInvestors() public view virtual returns (uint256);\n\n    function setMinimumTotalInvestors(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMinimumHoldingsPerInvestor() public view virtual returns (uint256);\n\n    function setMinimumHoldingsPerInvestor(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getMaximumHoldingsPerInvestor() public view virtual returns (uint256);\n\n    function setMaximumHoldingsPerInvestor(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getEURetailInvestorsLimit() public view virtual returns (uint256);\n\n    function setEURetailInvestorsLimit(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getUSLockPeriod() public view virtual returns (uint256);\n\n    function setUSLockPeriod(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getForceFullTransfer() public view virtual returns (bool);\n\n    function setForceFullTransfer(\n        bool _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getForceAccredited() public view virtual returns (bool);\n\n    function setForceAccredited(\n        bool _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function setForceAccreditedUS(\n        bool _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getForceAccreditedUS() public view virtual returns (bool);\n\n    function setWorldWideForceFullTransfer(\n        bool _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getWorldWideForceFullTransfer() public view virtual returns (bool);\n\n    function getAuthorizedSecurities() public view virtual returns (uint256);\n\n    function setAuthorizedSecurities(\n        uint256 _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getDisallowBackDating() public view virtual returns (bool);\n\n    function setDisallowBackDating(\n        bool _value /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function setAll(\n        uint256[] calldata _uint_values,\n        bool[] calldata _bool_values /*onlyTransferAgentOrAbove*/\n    ) public virtual;\n\n    function getAll() public view virtual returns (uint256[] memory, bool[] memory);\n}\n"},"contracts/compliance/IDSComplianceService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSComplianceService {\n\n    uint256 internal constant NONE = 0;\n    uint256 internal constant US = 1;\n    uint256 internal constant EU = 2;\n    uint256 internal constant FORBIDDEN = 4;\n    uint256 internal constant JP = 8;\n    string internal constant TOKEN_PAUSED = \"Token Paused\";\n    string internal constant NOT_ENOUGH_TOKENS = \"Not Enough Tokens\";\n    string internal constant TOKENS_LOCKED = \"Tokens Locked\";\n    string internal constant WALLET_NOT_IN_REGISTRY_SERVICE = \"Wallet not in registry Service\";\n    string internal constant DESTINATION_RESTRICTED = \"Destination restricted\";\n    string internal constant VALID = \"Valid\";\n    string internal constant HOLD_UP = \"Under lock-up\";\n    string internal constant ONLY_FULL_TRANSFER = \"Only Full Transfer\";\n    string internal constant FLOWBACK = \"Flowback\";\n    string internal constant MAX_INVESTORS_IN_CATEGORY = \"Max Investors in category\";\n    string internal constant AMOUNT_OF_TOKENS_UNDER_MIN = \"Amount of tokens under min\";\n    string internal constant AMOUNT_OF_TOKENS_ABOVE_MAX = \"Amount of tokens above max\";\n    string internal constant ONLY_ACCREDITED = \"Only accredited\";\n    string internal constant ONLY_US_ACCREDITED = \"Only us accredited\";\n    string internal constant NOT_ENOUGH_INVESTORS = \"Not enough investors\";\n    string internal constant MAX_AUTHORIZED_SECURITIES_EXCEEDED = \"Max authorized securities exceeded\";\n\n    function initialize() public virtual;\n\n    function adjustInvestorCountsAfterCountryChange(\n        string memory _id,\n        string memory _country,\n        string memory _prevCountry\n    ) public virtual returns (bool);\n\n    //*****************************************\n    // TOKEN ACTION VALIDATIONS\n    //*****************************************\n\n    function validateTransfer(\n        address _from,\n        address _to,\n        uint256 _value /*onlyToken*/\n    ) public virtual returns (bool);\n\n    function validateTransfer(\n        address _from,\n        address _to,\n        uint256 _value, /*onlyToken*/\n        bool _pausedToken,\n        uint256 _balanceFrom\n    ) public virtual returns (bool);\n\n    function validateIssuance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime /*onlyToken*/\n    ) public virtual returns (bool);\n\n    function validateIssuanceWithNoCompliance(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime /*onlyToken*/\n    ) public virtual returns (bool);\n\n    function validateBurn(\n        address _who,\n        uint256 _value /*onlyToken*/\n    ) public virtual returns (bool);\n\n    function validateSeize(\n        address _from,\n        address _to,\n        uint256 _value /*onlyToken*/\n    ) public virtual returns (bool);\n\n    function preIssuanceCheck(address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);\n\n    function preTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual returns (uint256 code, string memory reason);\n\n    function newPreTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value,\n        uint256 _balanceFrom,\n        bool _pausedToken\n    ) public view virtual returns (uint256 code, string memory reason);\n\n    function preInternalTransferCheck(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public view virtual returns (uint256 code, string memory reason);\n\n    function validateIssuanceTime(uint256 _issuanceTime) public view virtual returns (uint256 issuanceTime);\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        uint64 _lockTime\n    ) public view virtual returns (uint256);\n}\n"},"contracts/compliance/IDSComplianceServicePartitioned.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSComplianceService.sol\";\n\nabstract contract IDSComplianceServicePartitioned is IDSComplianceService {\n\n    function initialize() public virtual override;\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        bool _checkFlowback\n    ) public view virtual returns (uint256 transferable);\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        bool _checkFlowback,\n        bytes32 _partition\n    ) public view virtual returns (uint256);\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        address _to\n    ) public view virtual returns (uint256 transferable);\n\n    function getComplianceTransferableTokens(\n        address _who,\n        uint256 _time,\n        address _to,\n        bytes32 _partition\n    ) public view virtual returns (uint256);\n}\n"},"contracts/compliance/IDSLockManager.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSLockManager {\n\n    function initialize() public virtual;\n\n    modifier validLock(uint256 _valueLocked, uint256 _releaseTime) {\n        require(_valueLocked > 0, \"Value is zero\");\n        require(_releaseTime == 0 || _releaseTime > uint256(block.timestamp), \"Release time is in the past\");\n        _;\n    }\n\n    event Locked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);\n    event Unlocked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);\n\n    event HolderLocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);\n    event HolderUnlocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);\n    /**\n     * @dev creates a lock record for wallet address\n     * @param _to address to lock the tokens at\n     * @param _valueLocked value of tokens to lock\n     * @param _reason reason for lock\n     * @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)\n     * Note: The user MAY have at a certain time more locked tokens than actual tokens\n     */\n\n    function addManualLockRecord(\n        address _to,\n        uint256 _valueLocked,\n        string calldata _reason,\n        uint256 _releaseTime /*issuerOrAboveOrToken*/\n    ) public virtual;\n\n    /**\n     * @dev creates a lock record for investor Id\n     * @param _investor investor id to lock the tokens at\n     * @param _valueLocked value of tokens to lock\n     * @param _reasonCode reason code for lock\n     * @param _reasonString reason for lock\n     * @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)\n     * Note: The user MAY have at a certain time more locked tokens than actual tokens\n     */\n\n    function createLockForInvestor(\n        string memory _investor,\n        uint256 _valueLocked,\n        uint256 _reasonCode,\n        string calldata _reasonString,\n        uint256 _releaseTime /*onlyIssuerOrAboveOrToken*/\n    ) public virtual;\n\n    /**\n     * @dev Releases a specific lock record for a wallet\n     * @param _to address to release the tokens for\n     * @param _lockIndex the index of the lock to remove\n     *\n     * note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.\n     * @return true on success\n     */\n    function removeLockRecord(\n        address _to,\n        uint256 _lockIndex /*issuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Releases a specific lock record for a investor\n     * @param _investorId investor id to release the tokens for\n     * @param _lockIndex the index of the lock to remove\n     *\n     * note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.\n     * @return true on success\n     */\n    function removeLockRecordForInvestor(\n        string memory _investorId,\n        uint256 _lockIndex /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Get number of locks currently associated with an address\n     * @param _who address to get count for\n     *\n     * @return number of locks\n     *\n     * Note - a lock can be inactive (due to its time expired) but still exists for a specific address\n     */\n    function lockCount(address _who) public view virtual returns (uint256);\n\n    /**\n     * @dev Get number of locks currently associated with a investor\n     * @param _investorId investor id to get count for\n     *\n     * @return number of locks\n     *\n     * Note - a lock can be inactive (due to its time expired) but still exists for a specific address\n     */\n\n    function lockCountForInvestor(string memory _investorId) public view virtual returns (uint256);\n\n    /**\n     * @dev Get details of a specific lock associated with an address\n     * can be used to iterate through the locks of a user\n     * @param _who address to get token lock for\n     * @param _lockIndex the 0 based index of the lock.\n     * @return reasonCode the reason code\n     * @return reasonString the reason for the lock\n     * @return value the value of tokens locked\n     * @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)\n     *\n     * Note - a lock can be inactive (due to its time expired) but still exists for a specific address\n     */\n    function lockInfo(address _who, uint256 _lockIndex) public view virtual returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);\n\n    /**\n     * @dev Get details of a specific lock associated with a investor\n     * can be used to iterate through the locks of a user\n     * @param _investorId investorId to get token lock for\n     * @param _lockIndex the 0 based index of the lock.\n     * @return reasonCode the reason code\n     * @return reasonString the reason for the lock\n     * @return value the value of tokens locked\n     * @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)\n     *\n     * Note - a lock can be inactive (due to its time expired) but still exists for a specific address\n     */\n    function lockInfoForInvestor(\n        string memory _investorId,\n        uint256 _lockIndex\n    ) public view virtual  returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);\n\n    /**\n     * @dev get total number of transferable tokens for a wallet, at a certain time\n     * @param _who address to get number of transferable tokens for\n     * @param _time time to calculate for\n     */\n    function getTransferableTokens(address _who, uint256 _time) public view virtual returns (uint256);\n\n    /**\n     * @dev get total number of transferable tokens for a investor, at a certain time\n     * @param _investorId investor id\n     * @param _time time to calculate for\n     */\n    function getTransferableTokensForInvestor(string memory _investorId, uint256 _time) public view virtual returns (uint256);\n\n    /**\n     * @dev pause investor\n     * @param _investorId investor id\n     */\n    function lockInvestor(\n        string memory _investorId /*issuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev unpauses investor\n     * @param _investorId investor id\n     */\n    function unlockInvestor(\n        string memory _investorId /*issuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Returns true if paused, otherwise false\n     * @param _investorId investor id\n     */\n    function isInvestorLocked(string memory _investorId) public view virtual returns (bool);\n}\n"},"contracts/compliance/IDSLockManagerPartitioned.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSLockManager.sol\";\n\nabstract contract IDSLockManagerPartitioned {\n\n    event LockedPartition(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);\n    event UnlockedPartition(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);\n    event HolderLockedPartition(string investorId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);\n    event HolderUnlockedPartition(string investorId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);\n\n    function createLockForInvestor(\n        string memory _investorId,\n        uint256 _valueLocked,\n        uint256 _reasonCode,\n        string memory _reasonString,\n        uint256 _releaseTime,\n        bytes32 _partition\n    ) public virtual;\n\n    function addManualLockRecord(\n        address _to,\n        uint256 _valueLocked,\n        string memory _reason,\n        uint256 _releaseTime,\n        bytes32 _partition /*issuerOrAboveOrToken*/\n    ) public virtual;\n\n    function removeLockRecord(\n        address _to,\n        uint256 _lockIndex,\n        bytes32 _partition /*issuerOrAbove*/\n    ) public virtual returns (bool);\n\n    function removeLockRecordForInvestor(\n        string memory _investorId,\n        uint256 _lockIndex,\n        bytes32 _partition /*issuerOrAbove*/\n    ) public virtual returns (bool);\n\n    function lockCount(address _who, bytes32 _partition) public view virtual returns (uint256);\n\n    function lockInfo(\n        address _who,\n        uint256 _lockIndex,\n        bytes32 _partition\n    )\n        public\n        view\n        virtual\n        returns (\n            uint256 reasonCode,\n            string memory reasonString,\n            uint256 value,\n            uint256 autoReleaseTime\n        );\n\n    function lockCountForInvestor(string memory _investorId, bytes32 _partition) public view virtual returns (uint256);\n\n    function lockInfoForInvestor(\n        string memory _investorId,\n        uint256 _lockIndex,\n        bytes32 _partition\n    )\n        public\n        view\n        virtual\n        returns (\n            uint256 reasonCode,\n            string memory reasonString,\n            uint256 value,\n            uint256 autoReleaseTime\n        );\n\n    function getTransferableTokens(\n        address _who,\n        uint256 _time,\n        bytes32 _partition\n    ) public view virtual returns (uint256);\n\n    function getTransferableTokensForInvestor(\n        string memory _investorId,\n        uint256 _time,\n        bytes32 _partition\n    ) public view virtual returns (uint256);\n\n    /*************** Legacy functions ***************/\n    function createLockForHolder(\n        string memory _investorId,\n        uint256 _valueLocked,\n        uint256 _reasonCode,\n        string memory _reasonString,\n        uint256 _releaseTime,\n        bytes32 _partition\n    ) public virtual;\n\n    function removeLockRecordForHolder(\n        string memory _investorId,\n        uint256 _lockIndex,\n        bytes32 _partition\n    ) public virtual returns (bool);\n\n    function lockCountForHolder(string memory _holderId, bytes32 _partition) public view virtual returns (uint256);\n\n    function lockInfoForHolder(\n        string memory _holderId,\n        uint256 _lockIndex,\n        bytes32 _partition\n    )\n        public\n        view\n        virtual\n        returns (\n            uint256 reasonCode,\n            string memory reasonString,\n            uint256 value,\n            uint256 autoReleaseTime\n        );\n\n    function getTransferableTokensForHolder(\n        string memory _holderId,\n        uint256 _time,\n        bytes32 _partition\n    ) public view virtual returns (uint256);\n\n    /******************************/\n}\n"},"contracts/compliance/IDSPartitionsManager.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSPartitionsManager {\n\n    event PartitionCreated(uint256 _date, uint256 _region, bytes32 _partition);\n\n    function initialize() public virtual;\n\n    function ensurePartition(\n        uint256 _issuanceDate,\n        uint256 _region /*onlyIssuerOrAboveOrToken*/\n    ) public virtual returns (bytes32 partition);\n\n    function getPartition(bytes32 _partition) public view virtual returns (uint256 date, uint256 region);\n\n    function getPartitionIssuanceDate(bytes32 _partition) public view virtual returns (uint256);\n\n    function getPartitionRegion(bytes32 _partition) public view virtual returns (uint256);\n}\n"},"contracts/compliance/IDSWalletManager.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSWalletManager {\n\n    function initialize() public virtual;\n\n    // Special wallets constants\n    uint8 public constant NONE = 0;\n    uint8 public constant ISSUER = 1;\n    uint8 public constant PLATFORM = 2;\n    uint8 public constant EXCHANGE = 4;\n\n    /**\n     * @dev should be emitted when a special wallet is added.\n     */\n    event DSWalletManagerSpecialWalletAdded(address wallet, uint8 walletType, address sender);\n    /**\n     * @dev should be emitted when a special wallet is removed.\n     */\n    event DSWalletManagerSpecialWalletRemoved(address wallet, uint8 walletType, address sender);\n    /**\n     * @dev should be emitted when the number of reserved slots is set for a wallet.\n     */\n    event DSWalletManagerReservedSlotsSet(address wallet, string country, uint8 accreditationStatus, uint256 slots, address sender);\n\n    /**\n     * @dev Sets a wallet to be an special wallet. (internal)\n     * @param _wallet The address of the wallet.\n     * @param _type The type of the wallet.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function setSpecialWallet(address _wallet, uint8 _type) internal virtual returns (bool);\n\n    /**\n     * @dev gets a wallet type\n     * @param _wallet the address of the wallet to check.\n     */\n    function getWalletType(address _wallet) public view virtual returns (uint8);\n\n    /**\n     * @dev Returns true if it is platform wallet\n     * @param _wallet the address of the wallet to check.\n     */\n    function isPlatformWallet(address _wallet) external view virtual returns (bool);\n\n    /**\n     * @dev Returns true if it is special wallet\n     * @param _wallet the address of the wallet to check.\n     */\n    function isSpecialWallet(address _wallet) external view virtual returns (bool);\n\n    /**\n     * @dev Returns true if it is issuer special wallet\n     * @param _wallet the address of the wallet to check.\n     */\n    function isIssuerSpecialWallet(address _wallet) external view virtual returns (bool);\n\n    /**\n     * @dev Sets a wallet to be an issuer wallet.\n     * @param _wallet The address of the wallet.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function addIssuerWallet(\n        address _wallet /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Sets an array of wallets to be issuer wallets.\n     * @param _wallets The address of the wallets.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function addIssuerWallets(address[] memory _wallets) public virtual returns (bool);\n\n    /**\n     * @dev Sets a wallet to be a platform wallet.\n     * @param _wallet The address of the wallet.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function addPlatformWallet(\n        address _wallet /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Sets an array of wallets to be platforms wallet.\n     * @param _wallets The address of the wallets.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function addPlatformWallets(address[] memory _wallets) public virtual returns (bool);\n\n    /**\n     * @dev Sets a wallet to be an exchange wallet.\n     * @param _wallet The address of the wallet.\n     * @param _owner The address of the owner.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function addExchangeWallet(address _wallet, address _owner) public virtual returns (bool);\n\n    /**\n     * @dev Removes a special wallet.\n     * @param _wallet The address of the wallet.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function removeSpecialWallet(\n        address _wallet /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n}\n"},"contracts/data-stores/ComplianceConfigurationDataStore.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ServiceConsumerDataStore.sol\";\n\ncontract ComplianceConfigurationDataStore is ServiceConsumerDataStore {\n    mapping(string => uint256) public countriesCompliances;\n    uint256 public totalInvestorsLimit;\n    uint256 public minUSTokens;\n    uint256 public minEUTokens;\n    uint256 public usInvestorsLimit;\n    uint256 public jpInvestorsLimit;\n    uint256 public usAccreditedInvestorsLimit;\n    uint256 public nonAccreditedInvestorsLimit;\n    uint256 public maxUSInvestorsPercentage;\n    uint256 public blockFlowbackEndTime;\n    uint256 public nonUSLockPeriod;\n    uint256 public minimumTotalInvestors;\n    uint256 public minimumHoldingsPerInvestor;\n    uint256 public maximumHoldingsPerInvestor;\n    uint256 public euRetailInvestorsLimit;\n    uint256 public usLockPeriod;\n    bool public forceFullTransfer;\n    bool public forceAccreditedUS;\n    bool public forceAccredited;\n    bool public worldWideForceFullTransfer;\n    uint256 public authorizedSecurities;\n    bool public disallowBackDating;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[31] private __gap;\n}\n"},"contracts/data-stores/ComplianceServiceDataStore.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ServiceConsumerDataStore.sol\";\n\ncontract ComplianceServiceDataStore is ServiceConsumerDataStore {\n    uint256 internal totalInvestors;\n    uint256 internal accreditedInvestorsCount;\n    uint256 internal usAccreditedInvestorsCount;\n    uint256 internal usInvestorsCount;\n    uint256 internal jpInvestorsCount;\n    mapping(string => uint256) internal euRetailInvestorsCount;\n    mapping(string => uint256) internal issuancesCounters;\n    mapping(string => mapping(uint256 => uint256)) issuancesValues;\n    mapping(string => mapping(uint256 => uint256)) issuancesTimestamps;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[41] private __gap;\n}\n"},"contracts/data-stores/OmnibusTBEControllerDataStore.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ServiceConsumerDataStore.sol\";\n\ncontract OmnibusTBEControllerDataStore is ServiceConsumerDataStore {\n    address internal omnibusWallet;\n    bool internal isPartitionedToken;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},"contracts/data-stores/ServiceConsumerDataStore.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\ncontract ServiceConsumerDataStore {\n\n    mapping(uint256 => address) internal services;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},"contracts/data-stores/TokenDataStore.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./ServiceConsumerDataStore.sol\";\nimport '../token/TokenPartitionsLibrary.sol';\nimport '../token/TokenLibrary.sol';\n\ncontract TokenDataStore is ServiceConsumerDataStore {\n\n    TokenLibrary.TokenData internal tokenData;\n    mapping(address => mapping(address => uint256)) internal allowances;\n    mapping(uint256 => address) internal walletsList;\n    uint256 internal walletsCount;\n    mapping(address => uint256) internal walletsToIndexes;\n    TokenPartitionsLibrary.TokenPartitions internal partitionsManagement;\n    uint256 public cap;\n    string public name;\n    string public symbol;\n    uint8 public decimals;\n    TokenLibrary.SupportedFeatures public supportedFeatures;\n    bool internal paused;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[35] private __gap;\n}\n"},"contracts/omnibus/IDSOmnibusTBEController.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../service/ServiceConsumer.sol\";\nimport \"../data-stores/OmnibusTBEControllerDataStore.sol\";\n\nabstract contract IDSOmnibusTBEController {\n\n    function initialize(address _omnibusWallet, bool _isPartitionedToken) public virtual;\n\n    function bulkIssuance(\n        uint256 value,\n        uint256 issuanceTime,\n        uint256 totalInvestors,\n        uint256 accreditedInvestors,\n        uint256 usAccreditedInvestors,\n        uint256 usTotalInvestors,\n        uint256 jpTotalInvestors,\n        bytes32[] calldata euRetailCountries,\n        uint256[] calldata euRetailCountryCounts\n    ) public virtual;\n\n    function bulkBurn(\n        uint256 value,\n        uint256 totalInvestors,\n        uint256 accreditedInvestors,\n        uint256 usAccreditedInvestors,\n        uint256 usTotalInvestors,\n        uint256 jpTotalInvestors,\n        bytes32[] calldata euRetailCountries,\n        uint256[] calldata euRetailCountryCounts\n    ) public virtual;\n\n    function bulkTransfer(address[] calldata wallets, uint256[] calldata values) public virtual;\n\n    function adjustCounters(\n        int256 totalDelta,\n        int256 accreditedDelta,\n        int256 usAccreditedDelta,\n        int256 usTotalDelta,\n        int256 jpTotalDelta,\n        bytes32[] calldata euRetailCountries,\n        int256[] calldata euRetailCountryDeltas\n    ) public virtual;\n\n    function getOmnibusWallet() public view virtual returns (address);\n}\n"},"contracts/omnibus/IDSOmnibusWalletController.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nabstract contract IDSOmnibusWalletController {\n    uint8 public constant BENEFICIARY = 0;\n    uint8 public constant HOLDER_OF_RECORD = 1;\n\n    function initialize(address _omnibusWallet) public virtual;\n\n    function setAssetTrackingMode(uint8 _assetTrackingMode) public virtual;\n\n    function getAssetTrackingMode() public view virtual returns (uint8);\n\n    function isHolderOfRecord() public view virtual returns (bool);\n\n    function balanceOf(address _who) public view virtual returns (uint256);\n\n    function transfer(\n        address _from,\n        address _to,\n        uint256 _value /*onlyOperator*/\n    ) public virtual;\n\n    function deposit(\n        address _to,\n        uint256 _value /*onlyToken*/\n    ) public virtual;\n\n    function withdraw(\n        address _from,\n        uint256 _value /*onlyToken*/\n    ) public virtual;\n\n    function seize(\n        address _from,\n        uint256 _value /*onlyToken*/\n    ) public virtual;\n\n    function burn(\n        address _from,\n        uint256 _value /*onlyToken*/\n    ) public virtual;\n}\n"},"contracts/omnibus/OmnibusTBEController.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../data-stores/OmnibusTBEControllerDataStore.sol\";\nimport \"../compliance/ComplianceServiceRegulated.sol\";\nimport \"../compliance/ComplianceConfigurationService.sol\";\nimport \"../token/IDSTokenPartitioned.sol\";\nimport \"../utils/BaseDSContract.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ncontract OmnibusTBEController is IDSOmnibusTBEController, OmnibusTBEControllerDataStore, BaseDSContract {\n\n    using SafeERC20 for IDSToken;\n\n    string internal constant MAX_INVESTORS_IN_CATEGORY = \"Max investors in category\";\n\n    function initialize(address _omnibusWallet, bool _isPartitionedToken) public override onlyProxy initializer {\n        require(_omnibusWallet != address(0), \"Omnibus wallet can not be zero address\");\n        __BaseDSContract_init();\n\n        omnibusWallet = _omnibusWallet;\n        isPartitionedToken = _isPartitionedToken;\n    }\n\n    function bulkIssuance(\n        uint256 value,\n        uint256 issuanceTime,\n        uint256 totalInvestors,\n        uint256 accreditedInvestors,\n        uint256 usAccreditedInvestors,\n        uint256 usTotalInvestors,\n        uint256 jpTotalInvestors,\n        bytes32[] calldata euRetailCountries,\n        uint256[] calldata euRetailCountryCounts\n    ) public override onlyIssuerOrAbove {\n        require(euRetailCountries.length == euRetailCountryCounts.length, 'EU Retail countries arrays do not match');\n        // Issue tokens\n        getToken().issueTokensCustom(omnibusWallet, value, issuanceTime, 0, '', 0);\n        addToCounters(\n            totalInvestors,\n            accreditedInvestors,\n            usAccreditedInvestors,\n            usTotalInvestors,\n            jpTotalInvestors,\n            euRetailCountries,\n            euRetailCountryCounts,\n            true\n        );\n        emitTBEOperationEvent(totalInvestors, accreditedInvestors, usAccreditedInvestors, usTotalInvestors, jpTotalInvestors, true);\n    }\n\n    function bulkBurn(\n        uint256 value,\n        uint256 totalInvestors,\n        uint256 accreditedInvestors,\n        uint256 usAccreditedInvestors,\n        uint256 usTotalInvestors,\n        uint256 jpTotalInvestors,\n        bytes32[] calldata euRetailCountries,\n        uint256[] calldata euRetailCountryCounts\n    ) public override onlyTransferAgentOrAbove {\n        require(euRetailCountries.length == euRetailCountryCounts.length, 'EU Retail countries arrays do not match');\n\n        if (isPartitionedToken) {\n            IDSTokenPartitioned token = IDSTokenPartitioned(getDSService(DS_TOKEN));\n            uint256 pendingBurn = value;\n            uint256 currentPartitionBalance;\n            bytes32 partition;\n            while (pendingBurn > 0) {\n                require(token.partitionCountOf(omnibusWallet) > 0, 'Not enough tokens in partitions to burn the required value');\n                partition = token.partitionOf(omnibusWallet, 0);\n                currentPartitionBalance = token.balanceOfByPartition(omnibusWallet, partition);\n                require(currentPartitionBalance > 0, 'Not enough tokens in remaining partitions to burn the required value');\n                uint256 amountToBurn = currentPartitionBalance >= pendingBurn ? pendingBurn : currentPartitionBalance;\n                token.burnByPartition(omnibusWallet, amountToBurn, 'Omnibus burn by partition', partition);\n                pendingBurn = pendingBurn - amountToBurn;\n            }\n        } else {\n            // Burn non partitioned tokens\n            getToken().burn(omnibusWallet, value, 'Omnibus');\n        }\n\n        emitTBEOperationEvent(totalInvestors, accreditedInvestors, usAccreditedInvestors, usTotalInvestors, jpTotalInvestors, false);\n    }\n\n    function bulkTransfer(address[] calldata wallets, uint256[] calldata values) public override onlyIssuerOrTransferAgentOrAbove {\n        require(wallets.length == values.length, 'Wallets and values lengths do not match');\n        for (uint i = 0; i < wallets.length; i++) {\n            getToken().safeTransferFrom(omnibusWallet, wallets[i], values[i]);\n        }\n    }\n\n    function internalTBETransfer(\n        string memory externalId,\n        int256 totalDelta,\n        int256 accreditedDelta,\n        int256 usAccreditedDelta,\n        int256 usTotalDelta,\n        int256 jpTotalDelta,\n        bytes32[] calldata euRetailCountries,\n        int256[] calldata euRetailCountryDeltas\n    ) public onlyIssuerOrTransferAgentOrAbove {\n        adjustCounters(\n            totalDelta,\n            accreditedDelta,\n            usAccreditedDelta,\n            usTotalDelta,\n            jpTotalDelta,\n            euRetailCountries,\n            euRetailCountryDeltas\n        );\n        getToken().emitOmnibusTBETransferEvent(omnibusWallet, externalId);\n    }\n\n    function adjustCounters(\n        int256 totalDelta,\n        int256 accreditedDelta,\n        int256 usAccreditedDelta,\n        int256 usTotalDelta,\n        int256 jpTotalDelta,\n        bytes32[] calldata euRetailCountries,\n        int256[] calldata euRetailCountryDeltas\n    ) public override onlyIssuerOrTransferAgentOrAbove {\n        require(euRetailCountries.length == euRetailCountryDeltas.length, 'Array lengths do not match');\n\n        addToCounters(\n            totalDelta > 0 ? SafeCast.toUint256(totalDelta) : 0,\n            accreditedDelta > 0 ? SafeCast.toUint256(accreditedDelta) : 0,\n            usAccreditedDelta > 0 ? SafeCast.toUint256(usAccreditedDelta) : 0,\n            usTotalDelta > 0 ? SafeCast.toUint256(usTotalDelta) : 0,\n            jpTotalDelta > 0 ? SafeCast.toUint256(jpTotalDelta) : 0,\n            euRetailCountries,\n            getUintEuCountriesDeltas(euRetailCountryDeltas, true),\n            true\n        );\n\n        getToken().emitOmnibusTBEEvent(\n            omnibusWallet,\n            totalDelta,\n            accreditedDelta,\n            usAccreditedDelta,\n            usTotalDelta,\n            jpTotalDelta);\n    }\n\n    function getOmnibusWallet() public view override returns (address) {\n        return omnibusWallet;\n    }\n\n    function addToCounters(uint256 _totalInvestors, uint256 _accreditedInvestors,\n        uint256 _usAccreditedInvestors, uint256 _usTotalInvestors, uint256 _jpTotalInvestors, bytes32[] memory _euRetailCountries,\n        uint256[] memory _euRetailCountryCounts, bool _increase) internal returns (bool) {\n        if (_increase) {\n            ComplianceServiceRegulated cs = ComplianceServiceRegulated(getDSService(COMPLIANCE_SERVICE));\n            IDSComplianceConfigurationService ccs = IDSComplianceConfigurationService(getDSService(COMPLIANCE_CONFIGURATION_SERVICE));\n\n            require(ccs.getNonAccreditedInvestorsLimit() == 0 || (cs.getTotalInvestorsCount() - cs.getAccreditedInvestorsCount()\n            + _totalInvestors - _accreditedInvestors <= ccs.getNonAccreditedInvestorsLimit()), MAX_INVESTORS_IN_CATEGORY);\n\n            cs.setTotalInvestorsCount(increaseCounter(cs.getTotalInvestorsCount(), ccs.getTotalInvestorsLimit(), _totalInvestors));\n            cs.setAccreditedInvestorsCount(increaseCounter(cs.getAccreditedInvestorsCount(), ccs.getTotalInvestorsLimit(), _accreditedInvestors));\n            cs.setUSAccreditedInvestorsCount(increaseCounter(cs.getUSAccreditedInvestorsCount(), ccs.getUSAccreditedInvestorsLimit(), _usAccreditedInvestors));\n            cs.setUSInvestorsCount(increaseCounter(cs.getUSInvestorsCount(), ccs.getUSInvestorsLimit(), _usTotalInvestors));\n            cs.setJPInvestorsCount(increaseCounter(cs.getJPInvestorsCount(), ccs.getJPInvestorsLimit(), _jpTotalInvestors));\n            for (uint i = 0; i < _euRetailCountries.length; i++) {\n                string memory countryCode = bytes32ToString(_euRetailCountries[i]);\n                cs.setEURetailInvestorsCount(\n                    countryCode,\n                    increaseCounter(\n                        cs.getEURetailInvestorsCount(countryCode),\n                        ccs.getEURetailInvestorsLimit(),\n                        _euRetailCountryCounts[i]\n                    )\n                );\n            }\n        }\n\n        return true;\n    }\n\n    function emitTBEOperationEvent(uint256 _totalInvestors, uint256 _accreditedInvestors,\n        uint256 _usAccreditedInvestors, uint256 _usTotalInvestors, uint256 _jpTotalInvestors, bool /* _increase */) internal {\n        getToken().emitOmnibusTBEEvent(\n            omnibusWallet,\n            SafeCast.toInt256(_totalInvestors),\n            SafeCast.toInt256(_accreditedInvestors),\n            SafeCast.toInt256(_usAccreditedInvestors),\n            SafeCast.toInt256(_usTotalInvestors),\n            SafeCast.toInt256(_jpTotalInvestors)\n        );\n    }\n\n    function getUintEuCountriesDeltas(int256[] memory euCountryDeltas, bool increase) internal pure returns (uint256[] memory) {\n        uint256[] memory result = new uint256[](euCountryDeltas.length);\n\n        for (uint i = 0; i < euCountryDeltas.length; i++) {\n            if (increase) {\n                result[i] = euCountryDeltas[i] > 0 ? uint256(euCountryDeltas[i]) : 0;\n            } else {\n                result[i] = euCountryDeltas[i] < 0 ? uint256(euCountryDeltas[i] * - 1) : 0;\n            }\n        }\n        return result;\n    }\n\n    function increaseCounter(uint256 currentValue, uint256 currentLimit, uint256 delta) internal pure returns (uint256) {\n        uint256 result = currentValue + delta;\n        require(currentLimit == 0 || result <= currentLimit, MAX_INVESTORS_IN_CATEGORY);\n        return result;\n    }\n\n    function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) {\n        uint8 i = 0;\n        while (i < 32 && _bytes32[i] != 0) {\n            i++;\n        }\n        bytes memory bytesArray = new bytes(i);\n        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n            bytesArray[i] = _bytes32[i];\n        }\n        return string(bytesArray);\n    }\n}\n"},"contracts/registry/IDSRegistryService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../utils/CommonUtils.sol\";\nimport \"../omnibus/IDSOmnibusWalletController.sol\";\n\nabstract contract IDSRegistryService {\n\n    function initialize() public virtual;\n\n    event DSRegistryServiceInvestorAdded(string investorId, address sender);\n    event DSRegistryServiceInvestorRemoved(string investorId, address sender);\n    event DSRegistryServiceInvestorCountryChanged(string investorId, string country, address sender);\n    event DSRegistryServiceInvestorAttributeChanged(string investorId, uint256 attributeId, uint256 value, uint256 expiry, string proofHash, address sender);\n    event DSRegistryServiceWalletAdded(address wallet, string investorId, address sender);\n    event DSRegistryServiceWalletRemoved(address wallet, string investorId, address sender);\n    event DSRegistryServiceOmnibusWalletAdded(address omnibusWallet, string investorId, IDSOmnibusWalletController omnibusWalletController);\n    event DSRegistryServiceOmnibusWalletRemoved(address omnibusWallet, string investorId);\n\n    uint8 public constant NONE = 0;\n    uint8 public constant KYC_APPROVED = 1;\n    uint8 public constant ACCREDITED = 2;\n    uint8 public constant QUALIFIED = 4;\n    uint8 public constant PROFESSIONAL = 8;\n\n    uint8 public constant PENDING = 0;\n    uint8 public constant APPROVED = 1;\n    uint8 public constant REJECTED = 2;\n\n    uint8 public constant EXCHANGE = 4;\n\n    modifier investorExists(string memory _id) {\n        require(isInvestor(_id), \"Unknown investor\");\n        _;\n    }\n\n    modifier newInvestor(string memory _id) {\n        require(!CommonUtils.isEmptyString(_id), \"Investor id must not be empty\");\n        require(!isInvestor(_id), \"Investor already exists\");\n        _;\n    }\n\n    modifier walletExists(address _address) {\n        require(isWallet(_address), \"Unknown wallet\");\n        _;\n    }\n\n    modifier newWallet(address _address) {\n        require(!isWallet(_address), \"Wallet already exists\");\n        _;\n    }\n\n    modifier newOmnibusWallet(address _omnibusWallet) {\n        require(!isOmnibusWallet(_omnibusWallet), \"Omnibus wallet already exists\");\n        _;\n    }\n\n    modifier omnibusWalletExists(address _omnibusWallet) {\n        require(isOmnibusWallet(_omnibusWallet), \"Unknown omnibus wallet\");\n        _;\n    }\n\n    modifier walletBelongsToInvestor(address _address, string memory _id) {\n        require(CommonUtils.isEqualString(getInvestor(_address), _id), \"Wallet does not belong to investor\");\n        _;\n    }\n\n    function registerInvestor(\n        string calldata _id,\n        string calldata _collision_hash /*onlyExchangeOrAbove newInvestor(_id)*/\n    ) public virtual returns (bool);\n\n    function updateInvestor(\n        string calldata _id,\n        string calldata _collisionHash,\n        string memory _country,\n        address[] memory _wallets,\n        uint8[] memory _attributeIds,\n        uint256[] memory _attributeValues,\n        uint256[] memory _attributeExpirations /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    function removeInvestor(\n        string calldata _id /*onlyExchangeOrAbove investorExists(_id)*/\n    ) public virtual returns (bool);\n\n    function setCountry(\n        string calldata _id,\n        string memory _country /*onlyExchangeOrAbove investorExists(_id)*/\n    ) public virtual returns (bool);\n\n    function getCountry(string memory _id) public view virtual returns (string memory);\n\n    function getCollisionHash(string calldata _id) public view virtual returns (string memory);\n\n    function setAttribute(\n        string calldata _id,\n        uint8 _attributeId,\n        uint256 _value,\n        uint256 _expiry,\n        string memory _proofHash /*onlyExchangeOrAbove investorExists(_id)*/\n    ) public virtual returns (bool);\n\n    function getAttributeValue(string memory _id, uint8 _attributeId) public view virtual returns (uint256);\n\n    function getAttributeExpiry(string memory _id, uint8 _attributeId) public view virtual returns (uint256);\n\n    function getAttributeProofHash(string memory _id, uint8 _attributeId) public view virtual returns (string memory);\n\n    function addWallet(\n        address _address,\n        string memory _id /*onlyExchangeOrAbove newWallet(_address)*/\n    ) public virtual returns (bool);\n\n    function addWalletByInvestor(address _address) public virtual returns (bool);\n\n    function removeWallet(\n        address _address,\n        string memory _id /*onlyExchangeOrAbove walletExists walletBelongsToInvestor(_address, _id)*/\n    ) public virtual returns (bool);\n\n    function addOmnibusWallet(\n        string memory _id,\n        address _omnibusWallet,\n        IDSOmnibusWalletController _omnibusWalletController /*onlyIssuerOrAbove newOmnibusWallet*/\n    ) public virtual;\n\n    function removeOmnibusWallet(\n        string memory _id,\n        address _omnibusWallet /*onlyIssuerOrAbove omnibusWalletControllerExists*/\n    ) public virtual;\n\n    function getOmnibusWalletController(address _omnibusWallet) public view virtual returns (IDSOmnibusWalletController);\n\n    function isOmnibusWallet(address _omnibusWallet) public view virtual returns (bool);\n\n    function getInvestor(address _address) public view virtual returns (string memory);\n\n    function getInvestorDetails(address _address) public view virtual returns (string memory, string memory);\n\n    function getInvestorDetailsFull(string memory _id)\n        public\n        view\n        virtual\n        returns (string memory, uint256[] memory, uint256[] memory, string memory, string memory, string memory, string memory);\n\n    function isInvestor(string memory _id) public view virtual returns (bool);\n\n    function isWallet(address _address) public view virtual returns (bool);\n\n    function isAccreditedInvestor(string calldata _id) external view virtual returns (bool);\n\n    function isQualifiedInvestor(string calldata _id) external view virtual returns (bool);\n\n    function isAccreditedInvestor(address _wallet) external view virtual returns (bool);\n\n    function isQualifiedInvestor(address _wallet) external view virtual returns (bool);\n\n    function getInvestors(address _from, address _to) external view virtual returns (string memory, string memory);\n}\n"},"contracts/service/IDSServiceConsumer.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../omnibus/IDSOmnibusWalletController.sol\";\n\nabstract contract IDSServiceConsumer {\n\n    uint256 public constant TRUST_SERVICE = 1;\n    uint256 public constant DS_TOKEN = 2;\n    uint256 public constant REGISTRY_SERVICE = 4;\n    uint256 public constant COMPLIANCE_SERVICE = 8;\n    uint256 public constant UNUSED_1 = 16;\n    uint256 public constant WALLET_MANAGER = 32;\n    uint256 public constant LOCK_MANAGER = 64;\n    uint256 public constant PARTITIONS_MANAGER = 128;\n    uint256 public constant COMPLIANCE_CONFIGURATION_SERVICE = 256;\n    uint256 public constant TOKEN_ISSUER = 512;\n    uint256 public constant WALLET_REGISTRAR = 1024;\n    uint256 public constant OMNIBUS_TBE_CONTROLLER = 2048;\n    uint256 public constant TRANSACTION_RELAYER = 4096;\n    uint256 public constant TOKEN_REALLOCATOR = 8192;\n    uint256 public constant ISSUER_MULTICALL = 8194;\n    uint256 public constant TA_MULTICALL = 8195;\n    uint256 public constant SECURITIZE_SWAP = 16384;\n    \n    function getDSService(uint256 _serviceId) public view virtual returns (address);\n\n    function setDSService(\n        uint256 _serviceId,\n        address _address /*onlyMaster*/\n    ) public virtual returns (bool);\n\n    event DSServiceSet(uint256 serviceId, address serviceAddress);\n}\n"},"contracts/service/ServiceConsumer.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSServiceConsumer.sol\";\nimport \"../data-stores/ServiceConsumerDataStore.sol\";\nimport \"../token/IDSToken.sol\";\nimport \"../compliance/IDSWalletManager.sol\";\nimport \"../compliance/IDSLockManager.sol\";\nimport \"../compliance/IDSLockManagerPartitioned.sol\";\nimport \"../compliance/IDSComplianceService.sol\";\nimport \"../compliance/IDSPartitionsManager.sol\";\nimport \"../compliance/IDSComplianceConfigurationService.sol\";\nimport \"../registry/IDSRegistryService.sol\";\nimport \"../omnibus/IDSOmnibusTBEController.sol\";\nimport \"../trust/IDSTrustService.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n\nabstract contract ServiceConsumer is IDSServiceConsumer, ServiceConsumerDataStore, OwnableUpgradeable {\n\n    // Bring role constants to save gas both in deployment (less bytecode) and usage\n    uint8 public constant ROLE_NONE = 0;\n    uint8 public constant ROLE_MASTER = 1;\n    uint8 public constant ROLE_ISSUER = 2;\n    uint8 public constant ROLE_EXCHANGE = 4;\n    uint8 public constant ROLE_TRANSFER_AGENT = 8;\n\n    function __ServiceConsumer_init() public virtual onlyInitializing {\n        __Ownable_init(msg.sender);\n    }\n\n    modifier onlyMaster {\n        IDSTrustService trustManager = getTrustService();\n        require(owner() == msg.sender || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        _;\n    }\n\n    /**\n   * @dev Allow invoking functions only by the users who have the MASTER role or the ISSUER role or the TRANSFER AGENT role.\n   */\n    modifier onlyIssuerOrTransferAgentOrAbove() {\n        IDSTrustService trustManager = getTrustService();\n        require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        _;\n    }\n\n    modifier onlyIssuerOrAbove {\n        IDSTrustService trustManager = getTrustService();\n        require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        _;\n    }\n\n    modifier onlyTransferAgentOrAbove {\n        IDSTrustService trustManager = getTrustService();\n        require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        _;\n    }\n\n    modifier onlyExchangeOrAbove {\n        IDSTrustService trustManager = getTrustService();\n        require(\n            trustManager.getRole(msg.sender) == ROLE_EXCHANGE\n            || trustManager.getRole(msg.sender) == ROLE_ISSUER\n            || trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT\n            || trustManager.getRole(msg.sender) == ROLE_MASTER,\n            \"Insufficient trust level\"\n        );\n        _;\n    }\n\n    modifier onlyToken {\n        require(msg.sender == getDSService(DS_TOKEN), \"This function can only called by the associated token\");\n        _;\n    }\n\n    modifier onlyRegistry {\n        require(msg.sender == getDSService(REGISTRY_SERVICE), \"This function can only called by the registry service\");\n        _;\n    }\n\n    modifier onlyIssuerOrAboveOrToken {\n        if (msg.sender != getDSService(DS_TOKEN)) {\n            IDSTrustService trustManager = IDSTrustService(getDSService(TRUST_SERVICE));\n            require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        }\n        _;\n    }\n\n    modifier onlyTransferAgentOrAboveOrToken {\n        if (msg.sender != getDSService(DS_TOKEN)) {\n            IDSTrustService trustManager = IDSTrustService(getDSService(TRUST_SERVICE));\n            require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        }\n        _;\n    }\n\n    modifier onlyOmnibusWalletController(address omnibusWallet, IDSOmnibusWalletController omnibusWalletController) {\n        require(getRegistryService().getOmnibusWalletController(omnibusWallet) == omnibusWalletController, \"Wrong controller address\");\n        _;\n    }\n\n    modifier onlyTBEOmnibus {\n        require(msg.sender == address(getOmnibusTBEController()), \"Not authorized\");\n        _;\n    }\n\n    modifier onlyMasterOrTBEOmnibus {\n        IDSTrustService trustManager = getTrustService();\n        require(msg.sender == address(getOmnibusTBEController()) ||\n        owner() == msg.sender || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Not authorized\");\n        _;\n    }\n\n    modifier onlyOwnerOrIssuerOrAbove {\n        if(owner() != msg.sender) {\n            IDSTrustService trustManager = getTrustService();\n            require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, \"Insufficient trust level\");\n        }\n        _;\n    }\n\n    function getDSService(uint256 _serviceId) public view override returns (address) {\n        return services[_serviceId];\n    }\n\n    function setDSService(uint256 _serviceId, address _address) public override onlyMaster returns (bool) {\n        services[_serviceId] = _address;\n        emit DSServiceSet(_serviceId, _address);\n        return true;\n    }\n\n    function getToken() internal view returns (IDSToken) {\n        return IDSToken(getDSService(DS_TOKEN));\n    }\n\n    function getTrustService() internal view returns (IDSTrustService) {\n        return IDSTrustService(getDSService(TRUST_SERVICE));\n    }\n\n    function getWalletManager() internal view returns (IDSWalletManager) {\n        return IDSWalletManager(getDSService(WALLET_MANAGER));\n    }\n\n    function getLockManager() internal view returns (IDSLockManager) {\n        return IDSLockManager(getDSService(LOCK_MANAGER));\n    }\n\n    function getLockManagerPartitioned() internal view returns (IDSLockManagerPartitioned) {\n        return IDSLockManagerPartitioned(getDSService(LOCK_MANAGER));\n    }\n\n    function getComplianceService() internal view returns (IDSComplianceService) {\n        return IDSComplianceService(getDSService(COMPLIANCE_SERVICE));\n    }\n\n    function getRegistryService() internal view returns (IDSRegistryService) {\n        return IDSRegistryService(getDSService(REGISTRY_SERVICE));\n    }\n\n    function getPartitionsManager() internal view returns (IDSPartitionsManager) {\n        return IDSPartitionsManager(getDSService(PARTITIONS_MANAGER));\n    }\n\n    function getComplianceConfigurationService() internal view returns (IDSComplianceConfigurationService) {\n        return IDSComplianceConfigurationService(getDSService(COMPLIANCE_CONFIGURATION_SERVICE));\n    }\n\n    function getOmnibusTBEController() internal view returns (IDSOmnibusTBEController) {\n        return IDSOmnibusTBEController(getDSService(OMNIBUS_TBE_CONTROLLER));\n    }\n}\n"},"contracts/token/DSToken.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSToken.sol\";\nimport \"./StandardToken.sol\";\n\ncontract DSToken is StandardToken {\n    // using FeaturesLibrary for SupportedFeatures;\n    using TokenLibrary for TokenLibrary.SupportedFeatures;\n    uint256 internal constant OMNIBUS_NO_ACTION = 0;\n\n    function initialize(string calldata _name, string calldata _symbol, uint8 _decimals) public virtual override onlyProxy initializer {\n        __StandardToken_init();\n\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n    }\n\n    /******************************\n       TOKEN CONFIGURATION\n   *******************************/\n\n    function setFeature(uint8 featureIndex, bool enable) public onlyMaster {\n        supportedFeatures.setFeature(featureIndex, enable);\n    }\n\n    function setFeatures(uint256 features) public onlyMaster {\n        supportedFeatures.value = features;\n    }\n\n    function setCap(uint256 _cap) public override onlyTransferAgentOrAbove {\n        require(cap == 0, \"Token cap already set\");\n        require(_cap > 0);\n        cap = _cap;\n    }\n\n    function totalIssued() public view returns (uint256) {\n        return tokenData.totalIssued;\n    }\n\n    /******************************\n       TOKEN ISSUANCE (MINTING)\n   *******************************/\n\n    /**\n     * @dev Issues unlocked tokens\n     * @param _to address The address which is going to receive the newly issued tokens\n     * @param _value uint256 the value of tokens to issue\n     * @return true if successful\n     */\n    function issueTokens(\n        address _to,\n        uint256 _value /*onlyIssuerOrAbove*/\n    ) public override returns (bool) {\n        issueTokensCustom(_to, _value, block.timestamp, 0, \"\", 0);\n        return true;\n    }\n\n    /**\n     * @dev Issuing tokens from the fund\n     * @param _to address The address which is going to receive the newly issued tokens\n     * @param _value uint256 the value of tokens to issue\n     * @param _valueLocked uint256 value of tokens, from those issued, to lock immediately.\n     * @param _reason reason for token locking\n     * @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)\n     * @return true if successful\n     */\n    function issueTokensCustom(address _to, uint256 _value, uint256 _issuanceTime, uint256 _valueLocked, string memory _reason, uint64 _releaseTime)\n    public\n    virtual\n    override\n    returns (\n    /*onlyIssuerOrAbove*/\n        bool\n    )\n    {\n        uint256[] memory valuesLocked;\n        uint64[] memory releaseTimes;\n        if (_valueLocked > 0) {\n            valuesLocked = new uint256[](1);\n            releaseTimes = new uint64[](1);\n            valuesLocked[0] = _valueLocked;\n            releaseTimes[0] = _releaseTime;\n        }\n\n        issueTokensWithMultipleLocks(_to, _value, _issuanceTime, valuesLocked, _reason, releaseTimes);\n        return true;\n    }\n\n    function issueTokensWithMultipleLocks(address _to, uint256 _value, uint256 _issuanceTime, uint256[] memory _valuesLocked, string memory _reason, uint64[] memory _releaseTimes)\n    public\n    virtual\n    override\n    onlyIssuerOrAbove\n    returns (bool)\n    {\n        TokenLibrary.issueTokensCustom(tokenData, getCommonServices(), getLockManager(), _to, _value, _issuanceTime, _valuesLocked, _releaseTimes, _reason, cap);\n        emit Transfer(address(0), _to, _value);\n\n        checkWalletsForList(address(0), _to);\n        return true;\n    }\n\n    function issueTokensWithNoCompliance(address _to, uint256 _value) public virtual override onlyIssuerOrAbove {\n        require(getRegistryService().isWallet(_to), \"Unknown wallet\");\n        TokenLibrary.issueTokensWithNoCompliance(tokenData, getCommonServices(), _to, _value, block.timestamp, cap);\n        emit Transfer(address(0), _to, _value);\n    }\n\n    //*********************\n    // TOKEN BURNING\n    //*********************\n\n    function burn(address _who, uint256 _value, string calldata _reason) public virtual override onlyIssuerOrTransferAgentOrAbove {\n        TokenLibrary.burn(tokenData, getCommonServices(), _who, _value);\n        emit Burn(_who, _value, _reason);\n        emit Transfer(_who, address(0), _value);\n        checkWalletsForList(_who, address(0));\n    }\n\n    function omnibusBurn(address _omnibusWallet, address _who, uint256 _value, string calldata _reason) public override onlyTransferAgentOrAbove {\n        require(_value <= tokenData.walletsBalances[_omnibusWallet]);\n        TokenLibrary.omnibusBurn(tokenData, getCommonServices(), _omnibusWallet, _who, _value);\n        emit OmnibusBurn(_omnibusWallet, _who, _value, _reason, getAssetTrackingMode(_omnibusWallet));\n        emit Burn(_omnibusWallet, _value, _reason);\n        emit Transfer(_omnibusWallet, address(0), _value);\n        checkWalletsForList(_omnibusWallet, address(0));\n    }\n\n    //*********************\n    // TOKEN SEIZING\n    //*********************\n\n    function seize(address _from, address _to, uint256 _value, string calldata _reason) public virtual override onlyTransferAgentOrAbove {\n        TokenLibrary.seize(tokenData, getCommonServices(), _from, _to, _value);\n        emit Seize(_from, _to, _value, _reason);\n        emit Transfer(_from, _to, _value);\n        checkWalletsForList(_from, _to);\n    }\n\n    function omnibusSeize(address _omnibusWallet, address _from, address _to, uint256 _value, string calldata _reason) public override onlyTransferAgentOrAbove {\n        TokenLibrary.omnibusSeize(tokenData, getCommonServices(), _omnibusWallet, _from, _to, _value);\n        emit OmnibusSeize(_omnibusWallet, _from, _value, _reason, getAssetTrackingMode(_omnibusWallet));\n        emit Seize(_omnibusWallet, _to, _value, _reason);\n        emit Transfer(_omnibusWallet, _to, _value);\n        checkWalletsForList(_omnibusWallet, _to);\n    }\n\n    //*********************\n    // TRANSFER RESTRICTIONS\n    //*********************\n\n    /**\n     * @dev Checks whether it can transfer with the compliance manager, if not -throws.\n     */\n    modifier canTransfer(address _sender, address _receiver, uint256 _value) {\n        getComplianceService().validateTransfer(_sender, _receiver, _value, paused, super.balanceOf(_sender));\n        _;\n    }\n\n    /**\n     * @dev override for transfer with modifiers:\n     * whether the token is not paused (checked in super class)\n     * and that the sender is allowed to transfer tokens\n     * @param _to The address that will receive the tokens.\n     * @param _value The amount of tokens to be transferred.\n     */\n    function transfer(address _to, uint256 _value) public virtual override canTransfer(msg.sender, _to, _value) returns (bool) {\n        return postTransferImpl(super.transfer(_to, _value), msg.sender, _to, _value);\n    }\n\n    /**\n     * @dev override for transfer with modifiers:\n     * whether the token is not paused (checked in super class)\n     * and that the sender is allowed to transfer tokens\n     * @param _from The address that will send the tokens.\n     * @param _to The address that will receive the tokens.\n     * @param _value The amount of tokens to be transferred.\n     */\n    function transferFrom(address _from, address _to, uint256 _value) public virtual override canTransfer(_from, _to, _value) returns (bool) {\n        return postTransferImpl(super.transferFrom(_from, _to, _value), _from, _to, _value);\n    }\n\n    function postTransferImpl(bool _superResult, address _from, address _to, uint256 _value) internal returns (bool) {\n        if (_superResult) {\n            updateInvestorsBalancesOnTransfer(_from, _to, _value);\n        }\n\n        checkWalletsForList(_from, _to);\n\n        return _superResult;\n    }\n\n    //*********************\n    // WALLET ENUMERATION\n    //****\n\n    function getWalletAt(uint256 _index) public view override returns (address) {\n        require(_index > 0 && _index <= walletsCount);\n        return walletsList[_index];\n    }\n\n    function walletCount() public view override returns (uint256) {\n        return walletsCount;\n    }\n\n    function checkWalletsForList(address _from, address _to) private {\n        if (super.balanceOf(_from) == 0) {\n            removeWalletFromList(_from);\n        }\n        if (super.balanceOf(_to) > 0) {\n            addWalletToList(_to);\n        }\n    }\n\n    function addWalletToList(address _address) private {\n        //Check if it's already there\n        uint256 existingIndex = walletsToIndexes[_address];\n        if (existingIndex == 0) {\n            //If not - add it\n            uint256 index = walletsCount + 1;\n            walletsList[index] = _address;\n            walletsToIndexes[_address] = index;\n            walletsCount = index;\n        }\n    }\n\n    function removeWalletFromList(address _address) private {\n        //Make sure it's there\n        uint256 existingIndex = walletsToIndexes[_address];\n        if (existingIndex != 0) {\n            uint256 lastIndex = walletsCount;\n            if (lastIndex != existingIndex) {\n                //Put the last wallet instead of it (this will work even with 1 wallet in the list)\n                address lastWalletAddress = walletsList[lastIndex];\n                walletsList[existingIndex] = lastWalletAddress;\n                walletsToIndexes[lastWalletAddress] = existingIndex;\n            }\n\n            delete walletsToIndexes[_address];\n            delete walletsList[lastIndex];\n            walletsCount = lastIndex - 1;\n        }\n    }\n\n    //**************************************\n    // MISCELLANEOUS FUNCTIONS\n    //**************************************\n\n    function balanceOfInvestor(string memory _id) public view override returns (uint256) {\n        return tokenData.investorsBalances[_id];\n    }\n\n    function getAssetTrackingMode(address _omnibusWallet) internal view returns (uint8) {\n        return getRegistryService().getOmnibusWalletController(_omnibusWallet).getAssetTrackingMode();\n    }\n\n    function updateOmnibusInvestorBalance(address _omnibusWallet, address _wallet, uint256 _value, CommonUtils.IncDec _increase)\n    public\n    override\n    onlyOmnibusWalletController(_omnibusWallet, IDSOmnibusWalletController(msg.sender))\n    returns (bool)\n    {\n        return updateInvestorBalance(_wallet, _value, _increase);\n    }\n\n    function emitOmnibusTransferEvent(address _omnibusWallet, address _from, address _to, uint256 _value)\n    public\n    override\n    onlyOmnibusWalletController(_omnibusWallet, IDSOmnibusWalletController(msg.sender))\n    {\n        emit OmnibusTransfer(_omnibusWallet, _from, _to, _value, getAssetTrackingMode(_omnibusWallet));\n    }\n\n    function emitOmnibusTBEEvent(address omnibusWallet, int256 totalDelta, int256 accreditedDelta,\n        int256 usAccreditedDelta, int256 usTotalDelta, int256 jpTotalDelta) public override onlyTBEOmnibus {\n        emit OmnibusTBEOperation(omnibusWallet, totalDelta, accreditedDelta, usAccreditedDelta, usTotalDelta, jpTotalDelta);\n    }\n\n    function emitOmnibusTBETransferEvent(address omnibusWallet, string memory externalId) public override onlyTBEOmnibus {\n        emit OmnibusTBETransfer(omnibusWallet, externalId);\n    }\n\n    function updateInvestorsBalancesOnTransfer(address _from, address _to, uint256 _value) internal {\n        uint256 omnibusEvent = TokenLibrary.applyOmnibusBalanceUpdatesOnTransfer(tokenData, getRegistryService(), _from, _to, _value);\n        if (omnibusEvent == OMNIBUS_NO_ACTION) {\n            updateInvestorBalance(_from, _value, CommonUtils.IncDec.Decrease);\n            updateInvestorBalance(_to, _value, CommonUtils.IncDec.Increase);\n        }\n    }\n\n    function updateInvestorBalance(address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal override returns (bool) {\n        string memory investor = getRegistryService().getInvestor(_wallet);\n        if (!CommonUtils.isEmptyString(investor)) {\n            uint256 balance = balanceOfInvestor(investor);\n            if (_increase == CommonUtils.IncDec.Increase) {\n                balance += _value;\n            } else {\n                balance -= _value;\n            }\n            tokenData.investorsBalances[investor] = balance;\n        }\n\n        return true;\n    }\n\n    function preTransferCheck(address _from, address _to, uint256 _value) public view override returns (uint256 code, string memory reason) {\n        return getComplianceService().preTransferCheck(_from, _to, _value);\n    }\n\n    function getCommonServices() internal view returns (address[] memory) {\n        address[] memory services = new address[](3);\n        services[0] = getDSService(COMPLIANCE_SERVICE);\n        services[1] = getDSService(REGISTRY_SERVICE);\n        services[2] = getDSService(OMNIBUS_TBE_CONTROLLER);\n        return services;\n    }\n}\n"},"contracts/token/IDSToken.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/interfaces/IERC20.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"../utils/CommonUtils.sol\";\nimport \"../omnibus/IDSOmnibusWalletController.sol\";\n\nabstract contract IDSToken is IERC20, Initializable {\n    event Issue(address indexed to, uint256 value, uint256 valueLocked);\n    event Burn(address indexed burner, uint256 value, string reason);\n    event Seize(address indexed from, address indexed to, uint256 value, string reason);\n    event OmnibusDeposit(address indexed omnibusWallet, address to, uint256 value, uint8 assetTrackingMode);\n    event OmnibusWithdraw(address indexed omnibusWallet, address from, uint256 value, uint8 assetTrackingMode);\n    event OmnibusSeize(address indexed omnibusWallet, address from, uint256 value, string reason, uint8 assetTrackingMode);\n    event OmnibusBurn(address indexed omnibusWallet, address who, uint256 value, string reason, uint8 assetTrackingMode);\n    event OmnibusTransfer(address indexed omnibusWallet, address from, address to, uint256 value, uint8 assetTrackingMode);\n    event OmnibusTBEOperation(address indexed omnibusWallet, int256 totalDelta, int256 accreditedDelta,\n        int256 usAccreditedDelta, int256 usTotalDelta, int256 jpTotalDelta);\n    event OmnibusTBETransfer(address omnibusWallet, string externalId);\n\n    event WalletAdded(address wallet);\n    event WalletRemoved(address wallet);\n\n    function initialize(string calldata _name, string calldata _symbol, uint8 _decimals) public virtual;\n\n    /******************************\n       CONFIGURATION\n   *******************************/\n\n    /**\n     * @dev Sets the total issuance cap\n     * Note: The cap is compared to the total number of issued token, not the total number of tokens available,\n     * So if a token is burned, it is not removed from the \"total number of issued\".\n     * This call cannot be called again after it was called once.\n     * @param _cap address The address which is going to receive the newly issued tokens\n     */\n    function setCap(\n        uint256 _cap /*onlyMaster*/\n    ) public virtual;\n\n    /******************************\n       TOKEN ISSUANCE (MINTING)\n   *******************************/\n\n    /**\n     * @dev Issues unlocked tokens\n     * @param _to address The address which is going to receive the newly issued tokens\n     * @param _value uint256 the value of tokens to issue\n     * @return true if successful\n     */\n    function issueTokens(\n        address _to,\n        uint256 _value /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Issuing tokens from the fund\n     * @param _to address The address which is going to receive the newly issued tokens\n     * @param _value uint256 the value of tokens to issue\n     * @param _valueLocked uint256 value of tokens, from those issued, to lock immediately.\n     * @param _reason reason for token locking\n     * @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)\n     * @return true if successful\n     */\n    function issueTokensCustom(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime,\n        uint256 _valueLocked,\n        string memory _reason,\n        uint64 _releaseTime /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    function issueTokensWithMultipleLocks(\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime,\n        uint256[] memory _valuesLocked,\n        string memory _reason,\n        uint64[] memory _releaseTimes /*onlyIssuerOrAbove*/\n    ) public virtual returns (bool);\n\n    function issueTokensWithNoCompliance(address _to, uint256 _value) public virtual /*onlyIssuerOrAbove*/;\n\n    //*********************\n    // TOKEN BURNING\n    //*********************\n\n    function burn(\n        address _who,\n        uint256 _value,\n        string calldata _reason /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    function omnibusBurn(\n        address _omnibusWallet,\n        address _who,\n        uint256 _value,\n        string calldata _reason /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    //*********************\n    // TOKEN SIEZING\n    //*********************\n\n    function seize(\n        address _from,\n        address _to,\n        uint256 _value,\n        string calldata _reason /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    function omnibusSeize(\n        address _omnibusWallet,\n        address _from,\n        address _to,\n        uint256 _value,\n        string calldata\n        /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    //*********************\n    // WALLET ENUMERATION\n    //*********************\n\n    function getWalletAt(uint256 _index) public view virtual returns (address);\n\n    function walletCount() public view virtual returns (uint256);\n\n    //**************************************\n    // MISCELLANEOUS FUNCTIONS\n    //**************************************\n    function isPaused() public view virtual returns (bool);\n\n    function balanceOfInvestor(string memory _id) public view virtual returns (uint256);\n\n    function updateOmnibusInvestorBalance(\n        address _omnibusWallet,\n        address _wallet,\n        uint256 _value,\n        CommonUtils.IncDec _increase /*onlyOmnibusWalletController*/\n    ) public virtual returns (bool);\n\n    function emitOmnibusTransferEvent(\n        address _omnibusWallet,\n        address _from,\n        address _to,\n        uint256 _value /*onlyOmnibusWalletController*/\n    ) public virtual;\n\n    function emitOmnibusTBEEvent(address omnibusWallet, int256 totalDelta, int256 accreditedDelta,\n        int256 usAccreditedDelta, int256 usTotalDelta, int256 jpTotalDelta /*onlyTBEOmnibus*/\n    ) public virtual;\n\n    function emitOmnibusTBETransferEvent(address omnibusWallet, string memory externalId) public virtual;\n\n    function updateInvestorBalance(address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal virtual returns (bool);\n\n    function preTransferCheck(address _from, address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);\n}\n"},"contracts/token/IDSTokenPartitioned.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"./IDSToken.sol\";\n\nabstract contract IDSTokenPartitioned {\n\n    function balanceOfByPartition(address _who, bytes32 _partition) public view virtual returns (uint256);\n\n    function balanceOfInvestorByPartition(string memory _id, bytes32 _partition) public view virtual returns (uint256);\n\n    function partitionCountOf(address _who) public view virtual returns (uint256);\n\n    function partitionOf(address _who, uint256 _index) public view virtual returns (bytes32);\n\n    function transferByPartitions(address _to, uint256 _value, bytes32[] memory _partitions, uint256[] memory _values) public virtual returns (bool);\n\n    function transferFromByPartitions(address _from, address _to, uint256 _value, bytes32[] memory _partitions, uint256[] memory _values) public virtual returns (bool);\n\n    function burnByPartition(\n        address _who,\n        uint256 _value,\n        string calldata _reason,\n        bytes32 _partition /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    function seizeByPartition(\n        address _from,\n        address _to,\n        uint256 _value,\n        string calldata _reason,\n        bytes32 _partition /*onlyIssuerOrAbove*/\n    ) public virtual;\n\n    event TransferByPartition(address indexed from, address indexed to, uint256 value, bytes32 indexed partition);\n    event IssueByPartition(address indexed to, uint256 value, bytes32 indexed partition);\n    event BurnByPartition(address indexed burner, uint256 value, string reason, bytes32 indexed partition);\n    event SeizeByPartition(address indexed from, address indexed to, uint256 value, string reason, bytes32 indexed partition);\n}\n"},"contracts/token/StandardToken.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../data-stores/TokenDataStore.sol\";\nimport \"../omnibus/OmnibusTBEController.sol\";\n\nabstract contract StandardToken is IDSToken, TokenDataStore, BaseDSContract {\n    event Pause();\n    event Unpause();\n\n    modifier whenNotPaused() {\n        require(!paused, \"Contract is paused\");\n        _;\n    }\n\n    modifier whenPaused() {\n        require(paused, \"Contract is not paused\");\n        _;\n    }\n\n    function __StandardToken_init() public onlyProxy onlyInitializing {\n        __BaseDSContract_init();\n    }\n\n    function pause() public onlyTransferAgentOrAbove whenNotPaused {\n        paused = true;\n        emit Pause();\n    }\n\n    function unpause() public onlyTransferAgentOrAbove whenPaused {\n        paused = false;\n        emit Unpause();\n    }\n\n    function isPaused() public view override returns (bool) {\n        return paused;\n    }\n\n    /**\n     * @dev Gets the balance of the specified address.\n     * @param _owner The address to query the the balance of.\n     * @return An uint256 representing the amount owned by the passed address.\n     */\n    function balanceOf(address _owner) public view returns (uint256) {\n        return tokenData.walletsBalances[_owner];\n    }\n\n    function totalSupply() public view returns (uint256) {\n        return tokenData.totalSupply;\n    }\n\n    /**\n     * @dev transfer token for a specified address\n     * @param _to The address to transfer to.\n     * @param _value The amount to be transferred.\n     */\n    function transfer(address _to, uint256 _value) public virtual returns (bool) {\n        return transferImpl(msg.sender, _to, _value);\n    }\n\n    function transferFrom(\n        address _from,\n        address _to,\n        uint256 _value\n    ) public virtual returns (bool) {\n        IDSOmnibusTBEController tbeController = getOmnibusTBEController();\n        if (!(msg.sender == address(tbeController) && _from == tbeController.getOmnibusWallet())) {\n            require(_value <= allowances[_from][msg.sender], \"Not enough allowance\");\n            allowances[_from][msg.sender] -= _value;\n        }\n        return transferImpl(_from, _to, _value);\n    }\n\n    function transferImpl(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal returns (bool) {\n        require(_to != address(0));\n        require(_value <= tokenData.walletsBalances[_from]);\n\n        tokenData.walletsBalances[_from] -= _value;\n        tokenData.walletsBalances[_to] += _value;\n\n        emit Transfer(_from, _to, _value);\n\n        return true;\n    }\n\n    function approve(address _spender, uint256 _value) public returns (bool) {\n        allowances[msg.sender][_spender] = _value;\n        emit Approval(msg.sender, _spender, _value);\n        return true;\n    }\n\n    function allowance(address _owner, address _spender) public view returns (uint256) {\n        return allowances[_owner][_spender];\n    }\n\n    function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) {\n        allowances[msg.sender][_spender] = allowances[msg.sender][_spender] + _addedValue;\n        emit Approval(msg.sender, _spender, allowances[msg.sender][_spender]);\n        return true;\n    }\n\n    function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) {\n        uint256 oldValue = allowances[msg.sender][_spender];\n        if (_subtractedValue > oldValue) {\n            allowances[msg.sender][_spender] = 0;\n        } else {\n            allowances[msg.sender][_spender] = oldValue - _subtractedValue;\n        }\n        emit Approval(msg.sender, _spender, allowances[msg.sender][_spender]);\n        return true;\n    }\n}\n"},"contracts/token/TokenLibrary.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../service/ServiceConsumer.sol\";\n\nlibrary TokenLibrary {\n    event OmnibusDeposit(address indexed omnibusWallet, address to, uint256 value, uint8 assetTrackingMode);\n    event OmnibusWithdraw(address indexed omnibusWallet, address from, uint256 value, uint8 assetTrackingMode);\n    event Issue(address indexed to, uint256 value, uint256 valueLocked);\n\n    uint256 internal constant COMPLIANCE_SERVICE = 0;\n    uint256 internal constant REGISTRY_SERVICE = 1;\n    uint256 internal constant OMNIBUS_NO_ACTION = 0;\n    uint256 internal constant OMNIBUS_DEPOSIT = 1;\n    uint256 internal constant OMNIBUS_WITHDRAW = 2;\n\n    struct TokenData {\n        mapping(address => uint256) walletsBalances;\n        mapping(string => uint256) investorsBalances;\n        uint256 totalSupply;\n        uint256 totalIssued;\n    }\n\n    struct SupportedFeatures {\n        uint256 value;\n    }\n\n    function setFeature(SupportedFeatures storage supportedFeatures, uint8 featureIndex, bool enable) public {\n        uint256 base = 2;\n        uint256 mask = base**featureIndex;\n\n        // Enable only if the feature is turned off and disable only if the feature is turned on\n        if (enable && (supportedFeatures.value & mask == 0)) {\n            supportedFeatures.value = supportedFeatures.value ^ mask;\n        } else if (!enable && (supportedFeatures.value & mask >= 1)) {\n            supportedFeatures.value = supportedFeatures.value ^ mask;\n        }\n    }\n\n    function issueTokensCustom(\n        TokenData storage _tokenData,\n        address[] memory _services,\n        IDSLockManager _lockManager,\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime,\n        uint256[] memory _valuesLocked,\n        uint64[] memory _releaseTimes,\n        string memory _reason,\n        uint256 _cap\n    ) public returns (bool) {\n        //Check input values\n        require(_to != address(0), \"Invalid address\");\n        require(_value > 0, \"Value is zero\");\n        require(_valuesLocked.length == _releaseTimes.length, \"Wrong length of parameters\");\n\n        //Make sure we are not hitting the cap\n        require(_cap == 0 || _tokenData.totalIssued + _value <= _cap, \"Token Cap Hit\");\n\n        //Check issuance is allowed (and inform the compliance manager, possibly adding locks)\n        IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateIssuance(_to, _value, _issuanceTime);\n\n        _tokenData.totalSupply += _value;\n        _tokenData.totalIssued += _value;\n        _tokenData.walletsBalances[_to] += _value;\n        updateInvestorBalance(_tokenData, IDSRegistryService(_services[REGISTRY_SERVICE]), _to, _value, CommonUtils.IncDec.Increase);\n\n        uint256 totalLocked = 0;\n        for (uint256 i = 0; i < _valuesLocked.length; i++) {\n            totalLocked += _valuesLocked[i];\n            _lockManager.addManualLockRecord(_to, _valuesLocked[i], _reason, _releaseTimes[i]);\n        }\n        require(totalLocked <= _value, \"valueLocked must be smaller than value\");\n        emit Issue(_to, _value, totalLocked);\n        return true;\n    }\n\n    function issueTokensWithNoCompliance(\n        TokenData storage _tokenData,\n        address[] memory _services,\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime,\n        uint256 _cap\n    ) public returns (bool) {\n        //Make sure we are not hitting the cap\n        require(_cap == 0 || _tokenData.totalIssued + _value <= _cap, \"Token Cap Hit\");\n\n        //Check and inform issuance\n        IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateIssuanceWithNoCompliance(_to, _value, _issuanceTime);\n\n        _tokenData.totalSupply += _value;\n        _tokenData.totalIssued += _value;\n        _tokenData.walletsBalances[_to] += _value;\n        updateInvestorBalance(_tokenData, IDSRegistryService(_services[REGISTRY_SERVICE]), _to, _value, CommonUtils.IncDec.Increase);\n\n        emit Issue(_to, _value, 0);\n        return true;\n    }\n\n    modifier validSeizeParameters(TokenData storage _tokenData, address _from, address _to, uint256 _value) {\n        require(_from != address(0), \"Invalid address\");\n        require(_to != address(0), \"Invalid address\");\n        require(_value <= _tokenData.walletsBalances[_from], \"Not enough balance\");\n\n        _;\n    }\n\n    function burn(TokenData storage _tokenData, address[] memory _services, address _who, uint256 _value) public {\n        require(_value <= _tokenData.walletsBalances[_who], \"Not enough balance\");\n        // no need to require value <= totalSupply, since that would imply the\n        // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n        IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateBurn(_who, _value);\n\n        _tokenData.walletsBalances[_who] -= _value;\n        updateInvestorBalance(_tokenData, IDSRegistryService(_services[REGISTRY_SERVICE]), _who, _value, CommonUtils.IncDec.Decrease);\n        _tokenData.totalSupply -= _value;\n    }\n\n    function seize(TokenData storage _tokenData, address[] memory _services, address _from, address _to, uint256 _value)\n    public\n    validSeizeParameters(_tokenData, _from, _to, _value)\n    {\n        IDSRegistryService registryService = IDSRegistryService(_services[REGISTRY_SERVICE]);\n        IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateSeize(_from, _to, _value);\n        _tokenData.walletsBalances[_from] -= _value;\n        _tokenData.walletsBalances[_to] += _value;\n        updateInvestorBalance(_tokenData, registryService, _from, _value, CommonUtils.IncDec.Decrease);\n        updateInvestorBalance(_tokenData, registryService, _to, _value, CommonUtils.IncDec.Increase);\n    }\n\n    function omnibusBurn(TokenData storage _tokenData, address[] memory _services, address _omnibusWallet, address _who, uint256 _value) public {\n        IDSRegistryService registryService = IDSRegistryService(_services[REGISTRY_SERVICE]);\n        IDSOmnibusWalletController omnibusController = IDSRegistryService(_services[REGISTRY_SERVICE]).getOmnibusWalletController(_omnibusWallet);\n        _tokenData.walletsBalances[_omnibusWallet] -= _value;\n        omnibusController.burn(_who, _value);\n        decreaseInvestorBalanceOnOmnibusSeizeOrBurn(_tokenData, registryService, omnibusController, _omnibusWallet, _who, _value);\n        _tokenData.totalSupply -= _value;\n    }\n\n    function omnibusSeize(TokenData storage _tokenData, address[] memory _services, address _omnibusWallet, address _from, address _to, uint256 _value)\n    public\n    validSeizeParameters(_tokenData, _omnibusWallet, _to, _value)\n    {\n        IDSRegistryService registryService = IDSRegistryService(_services[REGISTRY_SERVICE]);\n        IDSOmnibusWalletController omnibusController = registryService.getOmnibusWalletController(_omnibusWallet);\n\n        _tokenData.walletsBalances[_omnibusWallet] -= _value;\n        _tokenData.walletsBalances[_to] += _value;\n        omnibusController.seize(_from, _value);\n        decreaseInvestorBalanceOnOmnibusSeizeOrBurn(_tokenData, registryService, omnibusController, _omnibusWallet, _from, _value);\n        updateInvestorBalance(_tokenData, registryService, _to, _value, CommonUtils.IncDec.Increase);\n    }\n\n    function decreaseInvestorBalanceOnOmnibusSeizeOrBurn(\n        TokenData storage _tokenData,\n        IDSRegistryService _registryService,\n        IDSOmnibusWalletController _omnibusController,\n        address _omnibusWallet,\n        address _from,\n        uint256 _value\n    ) internal {\n        if (_omnibusController.isHolderOfRecord()) {\n            updateInvestorBalance(_tokenData, _registryService, _omnibusWallet, _value, CommonUtils.IncDec.Decrease);\n        } else {\n            updateInvestorBalance(_tokenData, _registryService, _from, _value, CommonUtils.IncDec.Decrease);\n        }\n    }\n\n    function applyOmnibusBalanceUpdatesOnTransfer(TokenData storage _tokenData, IDSRegistryService _registryService, address _from, address _to, uint256 _value)\n    public\n    returns (uint256)\n    {\n        if (_registryService.isOmnibusWallet(_to)) {\n            IDSOmnibusWalletController omnibusWalletController = _registryService.getOmnibusWalletController(_to);\n            omnibusWalletController.deposit(_from, _value);\n            emit OmnibusDeposit(_to, _from, _value, omnibusWalletController.getAssetTrackingMode());\n\n            if (omnibusWalletController.isHolderOfRecord()) {\n                updateInvestorBalance(_tokenData, _registryService, _from, _value, CommonUtils.IncDec.Decrease);\n                updateInvestorBalance(_tokenData, _registryService, _to, _value, CommonUtils.IncDec.Increase);\n            }\n            return OMNIBUS_DEPOSIT;\n        } else if (_registryService.isOmnibusWallet(_from)) {\n            IDSOmnibusWalletController omnibusWalletController = _registryService.getOmnibusWalletController(_from);\n            omnibusWalletController.withdraw(_to, _value);\n            emit OmnibusWithdraw(_from, _to, _value, omnibusWalletController.getAssetTrackingMode());\n\n            if (omnibusWalletController.isHolderOfRecord()) {\n                updateInvestorBalance(_tokenData, _registryService, _from, _value, CommonUtils.IncDec.Decrease);\n                updateInvestorBalance(_tokenData, _registryService, _to, _value, CommonUtils.IncDec.Increase);\n            }\n            return OMNIBUS_WITHDRAW;\n        }\n        return OMNIBUS_NO_ACTION;\n    }\n\n    function updateInvestorBalance(TokenData storage _tokenData, IDSRegistryService _registryService, address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal returns (bool) {\n        string memory investor = _registryService.getInvestor(_wallet);\n        if (!CommonUtils.isEmptyString(investor)) {\n            uint256 balance = _tokenData.investorsBalances[investor];\n            if (_increase == CommonUtils.IncDec.Increase) {\n                balance += _value;\n            } else {\n                balance -= _value;\n            }\n            _tokenData.investorsBalances[investor] = balance;\n        }\n\n        return true;\n    }\n}\n"},"contracts/token/TokenPartitionsLibrary.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../utils/CommonUtils.sol\";\nimport \"../compliance/IDSComplianceServicePartitioned.sol\";\nimport \"../compliance/IDSLockManagerPartitioned.sol\";\nimport \"../registry/IDSRegistryService.sol\";\nimport \"../compliance/IDSComplianceConfigurationService.sol\";\nimport \"../compliance/IDSPartitionsManager.sol\";\nimport \"../omnibus/IDSOmnibusTBEController.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nlibrary TokenPartitionsLibrary {\n\n    uint256 internal constant COMPLIANCE_SERVICE = 0;\n    uint256 internal constant REGISTRY_SERVICE = 1;\n    uint256 internal constant OMNIBUS_TBE_CONTROLLER = 2;\n\n    event IssueByPartition(address indexed to, uint256 value, bytes32 indexed partition);\n    event TransferByPartition(address indexed from, address indexed to, uint256 value, bytes32 indexed partition);\n    struct AddressPartitions {\n        uint256 count;\n        mapping(bytes32 => uint256) toIndex;\n        mapping(uint256 => bytes32) partitions;\n        mapping(bytes32 => uint256) balances;\n    }\n\n    struct TokenPartitions {\n        mapping(address => AddressPartitions) walletPartitions;\n        mapping(string => mapping(bytes32 => uint256)) investorPartitionsBalances;\n    }\n\n    function issueTokensCustom(\n        TokenPartitions storage self,\n        IDSRegistryService _registry,\n        IDSComplianceConfigurationService _compConf,\n        IDSPartitionsManager _partitionsManager,\n        IDSLockManagerPartitioned _lockManager,\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime,\n        uint256[] memory _valuesLocked,\n        string memory _reason,\n        uint64[] memory _releaseTimes\n    ) public returns (bool) {\n        string memory investor = _registry.getInvestor(_to);\n        string memory country = _registry.getCountry(investor);\n        bytes32 partition = _partitionsManager.ensurePartition(_issuanceTime, _compConf.getCountryCompliance(country));\n        emit IssueByPartition(_to, _value, partition);\n        transferPartition(self, _registry, address(0), _to, _value, partition);\n        uint256 totalLocked = 0;\n        for (uint256 i = 0; i < _valuesLocked.length; i++) {\n            totalLocked += _valuesLocked[i];\n            _lockManager.createLockForInvestor(investor, _valuesLocked[i], 0, _reason, _releaseTimes[i], partition);\n        }\n        require(totalLocked <= _value, \"valueLocked must be smaller than value\");\n\n        return true;\n    }\n\n    function issueTokensWithNoCompliance(\n        TokenPartitions storage self,\n        IDSRegistryService _registry,\n        IDSComplianceConfigurationService _compConf,\n        IDSPartitionsManager _partitionsManager,\n        address _to,\n        uint256 _value,\n        uint256 _issuanceTime\n    ) public returns (bool) {\n        string memory investor = _registry.getInvestor(_to);\n        string memory country = _registry.getCountry(investor);\n        bytes32 partition = _partitionsManager.ensurePartition(_issuanceTime, _compConf.getCountryCompliance(country));\n        emit IssueByPartition(_to, _value, partition);\n        transferPartition(self, _registry, address(0), _to, _value, partition);\n        return true;\n    }\n\n    function setPartitionToAddressImpl(TokenPartitions storage self, address _who, uint256 _index, bytes32 _partition) internal returns (bool) {\n        self.walletPartitions[_who].partitions[_index] = _partition;\n        self.walletPartitions[_who].toIndex[_partition] = _index;\n        return true;\n    }\n\n    function addPartitionToAddress(TokenPartitions storage self, address _who, bytes32 _partition) internal {\n        uint256 partitionCount = self.walletPartitions[_who].count;\n        setPartitionToAddressImpl(self, _who, self.walletPartitions[_who].count, _partition);\n        self.walletPartitions[_who].count = partitionCount + 1;\n    }\n\n    function removePartitionFromAddress(TokenPartitions storage self, address _from, bytes32 _partition) internal {\n        uint256 oldIndex = self.walletPartitions[_from].toIndex[_partition];\n        uint256 lastPartitionIndex = self.walletPartitions[_from].count - 1;\n        bytes32 lastPartition = self.walletPartitions[_from].partitions[lastPartitionIndex];\n\n        setPartitionToAddressImpl(self, _from, oldIndex, lastPartition);\n\n        delete self.walletPartitions[_from].partitions[lastPartitionIndex];\n        delete self.walletPartitions[_from].toIndex[_partition];\n        delete self.walletPartitions[_from].balances[_partition];\n        self.walletPartitions[_from].count = self.walletPartitions[_from].count - 1;\n    }\n\n    function transferPartition(TokenPartitions storage self, IDSRegistryService _registry, address _from, address _to, uint256 _value, bytes32 _partition) public {\n        if (_from != address(0)) {\n            self.walletPartitions[_from].balances[_partition] = self.walletPartitions[_from].balances[_partition] - _value;\n            updateInvestorPartitionBalance(self, _registry, _from, _value, CommonUtils.IncDec.Decrease, _partition);\n            if (self.walletPartitions[_from].balances[_partition] == 0) {\n                removePartitionFromAddress(self, _from, _partition);\n            }\n        }\n\n        if (_to != address(0)) {\n            if (self.walletPartitions[_to].balances[_partition] == 0 && _value > 0) {\n                addPartitionToAddress(self, _to, _partition);\n            }\n            self.walletPartitions[_to].balances[_partition] += _value;\n            updateInvestorPartitionBalance(self, _registry, _to, _value, CommonUtils.IncDec.Increase, _partition);\n        }\n        emit TransferByPartition(_from, _to, _value, _partition);\n    }\n\n    function transferPartitions(TokenPartitions storage self, address[] memory _services, address _from, address _to, uint256 _value) public returns (bool) {\n        uint256 partitionCount = partitionCountOf(self, _from);\n        uint256 index = 0;\n        bool skipComplianceCheck = shouldSkipComplianceCheck(IDSRegistryService(_services[REGISTRY_SERVICE]),\n            IDSOmnibusTBEController(_services[OMNIBUS_TBE_CONTROLLER]), _from, _to);\n        while (_value > 0 && index < partitionCount) {\n            bytes32 partition = partitionOf(self, _from, index);\n            uint256 transferableInPartition = skipComplianceCheck\n                ? self.walletPartitions[_from].balances[partition]\n                : IDSComplianceServicePartitioned(_services[COMPLIANCE_SERVICE]).getComplianceTransferableTokens(_from, block.timestamp, _to, partition);\n            uint256 transferable = Math.min(_value, transferableInPartition);\n            if (transferable > 0) {\n                if (self.walletPartitions[_from].balances[partition] == transferable) {\n                    unchecked {\n                        --index;\n                        --partitionCount;\n                    }\n                }\n                transferPartition(self, IDSRegistryService(_services[REGISTRY_SERVICE]), _from, _to, transferable, partition);\n                _value -= transferable;\n            }\n            unchecked {\n                ++index;\n            }\n        }\n\n        require(_value == 0);\n\n        return true;\n    }\n\n    function transferPartitions(\n        TokenPartitions storage self,\n        address[] memory _services,\n        address _from,\n        address _to,\n        uint256 _value,\n        bytes32[] memory _partitions,\n        uint256[] memory _values\n    ) public returns (bool) {\n        require(_partitions.length == _values.length);\n        bool skipComplianceCheck = shouldSkipComplianceCheck(IDSRegistryService(_services[REGISTRY_SERVICE]),\n            IDSOmnibusTBEController(_services[OMNIBUS_TBE_CONTROLLER]), _from, _to);\n        for (uint256 index = 0; index < _partitions.length; ++index) {\n            if (!skipComplianceCheck) {\n                require(_values[index] <= IDSComplianceServicePartitioned(_services[COMPLIANCE_SERVICE]).getComplianceTransferableTokens(_from, block.timestamp, _to, _partitions[index]));\n            }\n            transferPartition(self, IDSRegistryService(_services[REGISTRY_SERVICE]), _from, _to, _values[index], _partitions[index]);\n            _value -= _values[index];\n        }\n\n        require(_value == 0);\n        return true;\n    }\n\n    function balanceOfByPartition(TokenPartitions storage self, address _who, bytes32 _partition) internal view returns (uint256) {\n        return self.walletPartitions[_who].balances[_partition];\n    }\n\n    function balanceOfInvestorByPartition(TokenPartitions storage self, string memory _id, bytes32 _partition) internal view returns (uint256) {\n        return self.investorPartitionsBalances[_id][_partition];\n    }\n\n    function partitionCountOf(TokenPartitions storage self, address _who) internal view returns (uint256) {\n        return self.walletPartitions[_who].count;\n    }\n\n    function partitionOf(TokenPartitions storage self, address _who, uint256 _index) internal view returns (bytes32) {\n        return self.walletPartitions[_who].partitions[_index];\n    }\n\n    function updateInvestorPartitionBalance(TokenPartitions storage self, IDSRegistryService _registry, address _wallet, uint256 _value, CommonUtils.IncDec _increase, bytes32 _partition)\n        internal\n        returns (bool)\n    {\n        string memory investor = _registry.getInvestor(_wallet);\n        if (!CommonUtils.isEmptyString(investor)) {\n            uint256 balance = self.investorPartitionsBalances[investor][_partition];\n            if (_increase == CommonUtils.IncDec.Increase) {\n                balance = balance + _value;\n            } else {\n                balance = balance - _value;\n            }\n            self.investorPartitionsBalances[investor][_partition] = balance;\n        }\n        return true;\n    }\n\n    function shouldSkipComplianceCheck(IDSRegistryService _registry, IDSOmnibusTBEController _omnibusTBEController, address _from, address _to) internal view returns (bool) {\n        return CommonUtils.isEqualString(_registry.getInvestor(_from), _registry.getInvestor(_to)) ||\n            (address(_omnibusTBEController) != address(0) && (_omnibusTBEController.getOmnibusWallet() == _from ||\n                _omnibusTBEController.getOmnibusWallet() == _to));\n    }\n}\n"},"contracts/trust/IDSTrustService.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\n/**\n * @title IDSTrustService\n * @dev An interface for a trust service which allows role-based access control for other contracts.\n */\n\nabstract contract IDSTrustService {\n\n    function initialize() public virtual;\n\n    /**\n     * @dev Should be emitted when a role is set for a user.\n     */\n    event DSTrustServiceRoleAdded(address targetAddress, uint8 role, address sender);\n    /**\n     * @dev Should be emitted when a role is removed for a user.\n     */\n    event DSTrustServiceRoleRemoved(address targetAddress, uint8 role, address sender);\n\n    // Role constants\n    uint8 public constant NONE = 0;\n    uint8 public constant MASTER = 1;\n    uint8 public constant ISSUER = 2;\n    uint8 public constant EXCHANGE = 4;\n    uint8 public constant TRANSFER_AGENT = 8;\n\n    /**\n     * @dev Transfers the ownership (MASTER role) of the contract.\n     * @param _address The address which the ownership needs to be transferred to.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function setServiceOwner(\n        address _address /*onlyMaster*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Sets a role for an array of wallets.\n     * @dev Should not be used for setting MASTER (use setServiceOwner) or role removal (use removeRole).\n     * @param _addresses The array of wallet whose role needs to be set.\n     * @param _roles The array of role to be set. The length and order must match with _addresses\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function setRoles(address[] calldata _addresses, uint8[] calldata _roles) public virtual returns (bool);\n\n    /**\n     * @dev Sets a role for a wallet.\n     * @dev Should not be used for setting MASTER (use setServiceOwner) or role removal (use removeRole).\n     * @param _address The wallet whose role needs to be set.\n     * @param _role The role to be set.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function setRole(\n        address _address,\n        uint8 _role /*onlyMasterOrIssuer*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Removes the role for a wallet.\n     * @dev Should not be used to remove MASTER (use setServiceOwner).\n     * @param _address The wallet whose role needs to be removed.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function removeRole(\n        address _address /*onlyMasterOrIssuer*/\n    ) public virtual returns (bool);\n\n    /**\n     * @dev Gets the role for a wallet.\n     * @param _address The wallet whose role needs to be fetched.\n     * @return A boolean that indicates if the operation was successful.\n     */\n    function getRole(address _address) public view virtual returns (uint8);\n\n    function addEntity(\n        string calldata _name,\n        address _owner /*onlyMasterOrIssuer onlyNewEntity onlyNewEntityOwner*/\n    ) public virtual;\n\n    function changeEntityOwner(\n        string calldata _name,\n        address _oldOwner,\n        address _newOwner /*onlyMasterOrIssuer onlyExistingEntityOwner*/\n    ) public virtual;\n\n    function addOperator(\n        string calldata _name,\n        address _operator /*onlyEntityOwnerOrAbove onlyNewOperator*/\n    ) public virtual;\n\n    function removeOperator(\n        string calldata _name,\n        address _operator /*onlyEntityOwnerOrAbove onlyExistingOperator*/\n    ) public virtual;\n\n    function addResource(\n        string calldata _name,\n        address _resource /*onlyMasterOrIssuer onlyExistingEntity onlyNewResource*/\n    ) public virtual;\n\n    function removeResource(\n        string calldata _name,\n        address _resource /*onlyMasterOrIssuer onlyExistingResource*/\n    ) public virtual;\n\n    function getEntityByOwner(address _owner) public view virtual returns (string memory);\n\n    function getEntityByOperator(address _operator) public view virtual returns (string memory);\n\n    function getEntityByResource(address _resource) public view virtual returns (string memory);\n\n    function isResourceOwner(address _resource, address _owner) public view virtual returns (bool);\n\n    function isResourceOperator(address _resource, address _operator) public view virtual returns (bool);\n}\n"},"contracts/utils/BaseDSContract.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nimport \"../service/ServiceConsumer.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol\";\n\nabstract contract BaseDSContract is UUPSUpgradeable, ServiceConsumer {\n\n    function __BaseDSContract_init() public onlyProxy onlyInitializing {\n        __UUPSUpgradeable_init();\n        __ServiceConsumer_init();\n    }\n\n    /**\n     * @dev required by the OZ UUPS module\n     */\n    function _authorizeUpgrade(address) internal override onlyMaster {}\n\n    /**\n     * @dev returns proxy ERC1967 implementation address\n     */\n    function getImplementationAddress() external view returns (address) {\n        return ERC1967Utils.getImplementation();\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function getInitializedVersion() external view returns (uint64) {\n        return _getInitializedVersion();\n    }\n\n}\n"},"contracts/utils/CommonUtils.sol":{"content":"/**\n * Copyright 2024 Securitize Inc. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity ^0.8.20;\n\nlibrary CommonUtils {\n  enum IncDec { Increase, Decrease }\n\n  function encodeString(string memory _str) internal pure returns (bytes32) {\n    return keccak256(abi.encodePacked(_str));\n  }\n\n  function isEqualString(string memory _str1, string memory _str2) internal pure returns (bool) {\n    return encodeString(_str1) == encodeString(_str2);\n  }\n\n  function isEmptyString(string memory _str) internal pure returns (bool) {\n    return isEqualString(_str, \"\");\n  }\n}\n"}},"matchId":"6377945","creationMatch":"match","runtimeMatch":"match","verifiedAt":"2025-05-22T14:34:29Z","match":"match","chainId":"1","address":"0xaf88485377cCa5e690e7DcB1BA81370F0B575156"}