creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/SickleRegistry.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\nimport \"./base/Admin.sol\";\n\nlibrary SickleRegistryEvents {\n    event CollectorChanged(address newCollector);\n    event FeesUpdated(bytes32[] feeHashes, uint256[] feesInBP);\n    event ReferralCodeCreated(bytes32 indexed code, address indexed referrer);\n\n    // Multicall caller and target whitelist status changes\n    event CallerStatusChanged(address caller, bool isWhitelisted);\n    event TargetStatusChanged(address target, bool isWhitelisted);\n}\n\n/// @title SickleRegistry contract\n/// @author vfat.tools\n/// @notice Manages the whitelisted contracts and the collector address\ncontract SickleRegistry is Admin {\n    /// ERRORS ///\n\n    error ArrayLengthMismatch(); // 0xa24a13a6\n    error FeeAboveMaxLimit(); // 0xd6cf7b5e\n    error InvalidReferralCode(); // 0xe55b4629\n\n    /// STORAGE ///\n\n    /// @notice Address of the fee collector\n    address public collector;\n\n    /// @notice Tracks the contracts that can be called through Sickle multicall\n    /// @return True if the contract is a whitelisted target\n    mapping(address => bool) public isWhitelistedTarget;\n\n    /// @notice Tracks the contracts that can call Sickle multicall\n    /// @return True if the contract is a whitelisted caller\n    mapping(address => bool) public isWhitelistedCaller;\n\n    /// @notice Keeps track of the referrers and their associated code\n    mapping(bytes32 => address) public referralCodes;\n\n    /// @notice Mapping for fee hashes (hash of the strategy contract addresses\n    /// and the function selectors) and their associated fees\n    /// @return The fee in basis points to apply to the transaction amount\n    mapping(bytes32 => uint256) public feeRegistry;\n\n    /// WRITE FUNCTIONS ///\n\n    /// @param admin_ Address of the admin\n    /// @param collector_ Address of the collector\n    constructor(address admin_, address collector_) Admin(admin_) {\n        collector = collector_;\n    }\n\n    /// @notice Updates the whitelist status for multiple multicall targets\n    /// @param targets Addresses of the contracts to update\n    /// @param isApproved New status for the contracts\n    function setWhitelistedTargets(\n        address[] calldata targets,\n        bool isApproved\n    ) external onlyAdmin {\n        for (uint256 i; i < targets.length;) {\n            isWhitelistedTarget[targets[i]] = isApproved;\n            emit SickleRegistryEvents.TargetStatusChanged(\n                targets[i], isApproved\n            );\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /// @notice Updates the fee collector address\n    /// @param newCollector Address of the new fee collector\n    function updateCollector(address newCollector) external onlyAdmin {\n        collector = newCollector;\n        emit SickleRegistryEvents.CollectorChanged(newCollector);\n    }\n\n    /// @notice Update the whitelist status for multiple multicall callers\n    /// @param callers Addresses of the callers\n    /// @param isApproved New status for the caller\n    function setWhitelistedCallers(\n        address[] calldata callers,\n        bool isApproved\n    ) external onlyAdmin {\n        for (uint256 i; i < callers.length;) {\n            isWhitelistedCaller[callers[i]] = isApproved;\n            emit SickleRegistryEvents.CallerStatusChanged(\n                callers[i], isApproved\n            );\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /// @notice Associates a referral code to the address of the caller\n    function setReferralCode(bytes32 referralCode) external {\n        if (referralCodes[referralCode] != address(0)) {\n            revert InvalidReferralCode();\n        }\n\n        referralCodes[referralCode] = msg.sender;\n        emit SickleRegistryEvents.ReferralCodeCreated(referralCode, msg.sender);\n    }\n\n    /// @notice Update the fees for multiple strategy functions\n    /// @param feeHashes Array of fee hashes\n    /// @param feesArray Array of fees to apply (in basis points)\n    function setFees(\n        bytes32[] calldata feeHashes,\n        uint256[] calldata feesArray\n    ) external onlyAdmin {\n        if (feeHashes.length != feesArray.length) {\n            revert ArrayLengthMismatch();\n        }\n\n        for (uint256 i = 0; i < feeHashes.length;) {\n            if (feesArray[i] <= 500) {\n                // maximum fee of 5%\n                feeRegistry[feeHashes[i]] = feesArray[i];\n            } else {\n                revert FeeAboveMaxLimit();\n            }\n            unchecked {\n                ++i;\n            }\n        }\n\n        emit SickleRegistryEvents.FeesUpdated(feeHashes, feesArray);\n    }\n}\n"
      },
      "contracts/base/Admin.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\n/// @title Admin contract\n/// @author vfat.tools\n/// @notice Provides an administration mechanism allowing restricted functions\nabstract contract Admin {\n    /// ERRORS ///\n\n    /// @notice Thrown when the caller is not the admin\n    error NotAdminError(); //0xb5c42b3b\n\n    /// EVENTS ///\n\n    /// @notice Emitted when a new admin is set\n    /// @param oldAdmin Address of the old admin\n    /// @param newAdmin Address of the new admin\n    event AdminSet(address oldAdmin, address newAdmin);\n\n    /// STORAGE ///\n\n    /// @notice Address of the current admin\n    address public admin;\n\n    /// MODIFIERS ///\n\n    /// @dev Restricts a function to the admin\n    modifier onlyAdmin() {\n        if (msg.sender != admin) revert NotAdminError();\n        _;\n    }\n\n    /// WRITE FUNCTIONS ///\n\n    /// @param admin_ Address of the admin\n    constructor(address admin_) {\n        emit AdminSet(admin, admin_);\n        admin = admin_;\n    }\n\n    /// @notice Sets a new admin\n    /// @dev Can only be called by the current admin\n    /// @param newAdmin Address of the new admin\n    function setAdmin(address newAdmin) external onlyAdmin {\n        emit AdminSet(admin, newAdmin);\n        admin = newAdmin;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "solmate/=lib/solmate/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@uniswap/v3-periphery/=lib/v3-periphery/",
        "@uniswap/v3-core/=lib/v3-core/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}