creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/RateLimitPolicy.sol": {
        "content": "pragma solidity ^0.8.0;\n\nimport \"kernel/sdk/moduleBase/PolicyBase.sol\";\nimport {packValidationData, ValidAfter, ValidUntil} from \"kernel/types/Types.sol\";\n\nenum Status {\n    NA,\n    Live,\n    Deprecated\n}\n\nstruct RateLimitConfig {\n    uint48 interval;\n    uint48 count;\n    ValidAfter startAt;\n}\n\ncontract RateLimitPolicy is PolicyBase {\n    mapping(address => uint256) public usedIds;\n    mapping(bytes32 id => mapping(address => Status)) public status;\n    mapping(bytes32 id => mapping(address kernel => RateLimitConfig)) public rateLimitConfigs;\n\n    function isInitialized(address wallet) external view override returns (bool) {\n        return usedIds[wallet] > 0;\n    }\n\n    function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp)\n        external\n        payable\n        override\n        returns (uint256)\n    {\n        require(status[id][msg.sender] == Status.Live);\n        RateLimitConfig memory config = rateLimitConfigs[id][msg.sender];\n        if (config.count == 0) {\n            return 1;\n        }\n        rateLimitConfigs[id][msg.sender].count = config.count - 1;\n        rateLimitConfigs[id][msg.sender].startAt = ValidAfter.wrap(ValidAfter.unwrap(config.startAt) + config.interval);\n        return packValidationData(config.startAt, ValidUntil.wrap(0));\n    }\n\n    function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)\n        external\n        view\n        override\n        returns (uint256)\n    {\n        require(status[id][msg.sender] == Status.Live);\n        return 0;\n    }\n\n    function _policyOninstall(bytes32 id, bytes calldata _data) internal override {\n        require(status[id][msg.sender] == Status.NA);\n        uint48 delay = uint48(bytes6(_data[0:6]));\n        uint48 count = uint48(bytes6(_data[6:12]));\n        uint48 startAt = uint48(bytes6(_data[12:18]));\n        rateLimitConfigs[id][msg.sender] = RateLimitConfig(delay, count, ValidAfter.wrap(startAt));\n        status[id][msg.sender] = Status.Live;\n        usedIds[msg.sender]++;\n    }\n\n    function _policyOnUninstall(bytes32 id, bytes calldata _data) internal override {\n        require(status[id][msg.sender] == Status.Live);\n        status[id][msg.sender] = Status.Deprecated;\n        usedIds[msg.sender]--;\n    }\n}\n"
      },
      "lib/kernel_v3/src/sdk/moduleBase/PolicyBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IPolicy} from \"../../interfaces/IERC7579Modules.sol\";\nimport {PackedUserOperation} from \"../../interfaces/PackedUserOperation.sol\";\n\nabstract contract PolicyBase is IPolicy {\n    function onInstall(bytes calldata data) external payable {\n        bytes32 id = bytes32(data[0:32]);\n        bytes calldata _data = data[32:];\n        _policyOninstall(id, _data);\n    }\n\n    function onUninstall(bytes calldata data) external payable {\n        bytes32 id = bytes32(data[0:32]);\n        bytes calldata _data = data[32:];\n        _policyOnUninstall(id, _data);\n    }\n\n    function isModuleType(uint256 id) external pure returns (bool) {\n        return id == 5;\n    }\n\n    function isInitialized(address) external view virtual returns (bool); // TODO : not sure if this is the right way to do it\n    function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp)\n        external\n        payable\n        virtual\n        returns (uint256);\n    function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)\n        external\n        view\n        virtual\n        returns (uint256);\n\n    function _policyOninstall(bytes32 id, bytes calldata _data) internal virtual;\n    function _policyOnUninstall(bytes32 id, bytes calldata _data) internal virtual;\n}\n"
      },
      "lib/kernel_v3/src/types/Types.sol": {
        "content": "pragma solidity ^0.8.23;\n\n// Custom type for improved developer experience\ntype ExecMode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ExecModeSelector is bytes4;\n\ntype ExecModePayload is bytes22;\n\nusing {eqModeSelector as ==} for ExecModeSelector global;\nusing {eqCallType as ==} for CallType global;\nusing {eqExecType as ==} for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n    return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n    return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) {\n    return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b);\n}\n\ntype ValidationMode is bytes1;\n\ntype ValidationId is bytes21;\n\ntype ValidationType is bytes1;\n\ntype PermissionId is bytes4;\n\ntype PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address\n\ntype PassFlag is bytes2;\n\nusing {vModeEqual as ==} for ValidationMode global;\nusing {vTypeEqual as ==} for ValidationType global;\nusing {vIdentifierEqual as ==} for ValidationId global;\nusing {vModeNotEqual as !=} for ValidationMode global;\nusing {vTypeNotEqual as !=} for ValidationType global;\nusing {vIdentifierNotEqual as !=} for ValidationId global;\n\n// nonce = uint192(key) + nonce\n// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey\n// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000\n// key = 0x00 + 0x01 + 0x1234...ff + 0x0000\n// key = 0x00 + 0x02 + ( ) + 0x000\n\nfunction vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) {\n    return ValidationMode.unwrap(a) == ValidationMode.unwrap(b);\n}\n\nfunction vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) {\n    return ValidationMode.unwrap(a) != ValidationMode.unwrap(b);\n}\n\nfunction vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) {\n    return ValidationType.unwrap(a) == ValidationType.unwrap(b);\n}\n\nfunction vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) {\n    return ValidationType.unwrap(a) != ValidationType.unwrap(b);\n}\n\nfunction vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) {\n    return ValidationId.unwrap(a) == ValidationId.unwrap(b);\n}\n\nfunction vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) {\n    return ValidationId.unwrap(a) != ValidationId.unwrap(b);\n}\n\ntype ValidationData is uint256;\n\ntype ValidAfter is uint48;\n\ntype ValidUntil is uint48;\n\nfunction getValidationResult(ValidationData validationData) pure returns (address result) {\n    assembly {\n        result := validationData\n    }\n}\n\nfunction packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) {\n    return uint256(ValidAfter.unwrap(validAfter)) << 208 | uint256(ValidUntil.unwrap(validUntil)) << 160;\n}\n\nfunction parseValidationData(uint256 validationData)\n    pure\n    returns (ValidAfter validAfter, ValidUntil validUntil, address result)\n{\n    assembly {\n        result := validationData\n        validUntil := and(shr(160, validationData), 0xffffffffffff)\n        switch iszero(validUntil)\n        case 1 { validUntil := 0xffffffffffff }\n        validAfter := shr(208, validationData)\n    }\n}\n"
      },
      "lib/kernel_v3/src/interfaces/IERC7579Modules.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nimport {PackedUserOperation} from \"./PackedUserOperation.sol\";\n\nuint256 constant VALIDATION_SUCCESS = 0;\nuint256 constant VALIDATION_FAILED = 1;\n\nuint256 constant MODULE_TYPE_VALIDATOR = 1;\nuint256 constant MODULE_TYPE_EXECUTOR = 2;\nuint256 constant MODULE_TYPE_FALLBACK = 3;\nuint256 constant MODULE_TYPE_HOOK = 4;\nuint256 constant MODULE_TYPE_POLICY = 5;\nuint256 constant MODULE_TYPE_SIGNER = 6;\nuint256 constant MODULE_TYPE_ACTION = 7;\n\ninterface IModule {\n    error AlreadyInitialized(address smartAccount);\n    error NotInitialized(address smartAccount);\n\n    /**\n     * @dev This function is called by the smart account during installation of the module\n     * @param data arbitrary data that may be required on the module during `onInstall`\n     * initialization\n     *\n     * MUST revert on error (i.e. if module is already enabled)\n     */\n    function onInstall(bytes calldata data) external payable;\n\n    /**\n     * @dev This function is called by the smart account during uninstallation of the module\n     * @param data arbitrary data that may be required on the module during `onUninstall`\n     * de-initialization\n     *\n     * MUST revert on error\n     */\n    function onUninstall(bytes calldata data) external payable;\n\n    /**\n     * @dev Returns boolean value if module is a certain type\n     * @param moduleTypeId the module type ID according the ERC-7579 spec\n     *\n     * MUST return true if the module is of the given type and false otherwise\n     */\n    function isModuleType(uint256 moduleTypeId) external view returns (bool);\n\n    /**\n     * @dev Returns if the module was already initialized for a provided smartaccount\n     */\n    function isInitialized(address smartAccount) external view returns (bool);\n}\n\ninterface IValidator is IModule {\n    error InvalidTargetAddress(address target);\n\n    /**\n     * @dev Validates a transaction on behalf of the account.\n     *         This function is intended to be called by the MSA during the ERC-4337 validaton phase\n     *         Note: solely relying on bytes32 hash and signature is not suffcient for some\n     * validation implementations (i.e. SessionKeys often need access to userOp.calldata)\n     * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.\n     * The MSA MUST clean up the userOp before sending it to the validator.\n     * @param userOpHash The hash of the user operation to be validated\n     * @return return value according to ERC-4337\n     */\n    function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)\n        external\n        payable\n        returns (uint256);\n\n    /**\n     * Validator can be used for ERC-1271 validation\n     */\n    function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data)\n        external\n        view\n        returns (bytes4);\n}\n\ninterface IExecutor is IModule {}\n\ninterface IHook is IModule {\n    function preCheck(address msgSender, bytes calldata msgData) external payable returns (bytes memory hookData);\n    function postCheck(bytes calldata hookData) external payable returns (bool success);\n}\n\ninterface IFallback is IModule {}\n\ninterface IPolicy is IModule {\n    function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp) external payable returns (uint256);\n    function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)\n        external\n        view\n        returns (uint256);\n}\n\ninterface ISigner is IModule {\n    function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)\n        external\n        payable\n        returns (uint256);\n    function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)\n        external\n        view\n        returns (bytes4);\n}\n\ninterface IAction is IModule {}\n"
      },
      "lib/kernel_v3/src/interfaces/PackedUserOperation.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\n/**\n * User Operation struct\n * @param sender                - The sender account of this request.\n * @param nonce                 - Unique value the sender uses to verify it is not a replay.\n * @param initCode              - If set, the account contract will be created by this constructor/\n * @param callData              - The method call to execute on this account.\n * @param accountGasLimits      - Packed gas limits for validateUserOp and gas limit passed to the callData method call.\n * @param preVerificationGas    - Gas not calculated by the handleOps method, but added to the gas paid.\n *                                Covers batch overhead.\n * @param gasFees                - packed gas fields maxFeePerGas and maxPriorityFeePerGas - Same as EIP-1559 gas parameter.\n * @param paymasterAndData      - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data\n *                                The paymaster will pay for the transaction instead of the sender.\n * @param signature             - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.\n */\nstruct PackedUserOperation {\n    address sender;\n    uint256 nonce;\n    bytes initCode;\n    bytes callData;\n    bytes32 accountGasLimits;\n    uint256 preVerificationGas;\n    bytes32 gasFees; //maxPriorityFee and maxFeePerGas;\n    bytes paymasterAndData;\n    bytes signature;\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "ds-test/=lib/kernel_v3/lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "kernel/=lib/kernel_v3/src/",
        "solady/=lib/kernel_v3/lib/solady/",
        "kernel_v3/=lib/kernel_v3/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "libraries": {}
    }
  }}