creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/quark-core/src/QuarkStateManager.sol": {
        "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.23;\n\nimport {IQuarkWallet} from \"quark-core/src/interfaces/IQuarkWallet.sol\";\n\n/**\n * @title Quark State Manager\n * @notice Contract for managing nonces and storage for Quark wallets, guaranteeing storage isolation across wallets\n *         and Quark operations\n * @author Compound Labs, Inc.\n */\ncontract QuarkStateManager {\n    event ClearNonce(address indexed wallet, uint96 nonce);\n\n    error NoActiveNonce();\n    error NoUnusedNonces();\n    error NonceAlreadySet();\n    error NonceScriptMismatch();\n\n    /// @notice Bit-packed structure of a nonce-script pair\n    struct NonceScript {\n        uint96 nonce;\n        address scriptAddress;\n    }\n\n    /// @notice Bit-packed nonce values\n    mapping(address wallet => mapping(uint256 bucket => uint256 bitset)) public nonces;\n\n    /// @notice Per-wallet-nonce address for preventing replays with changed script address\n    mapping(address wallet => mapping(uint96 nonce => address scriptAddress)) public nonceScriptAddress;\n\n    /// @notice Per-wallet-nonce storage space that can be utilized while a nonce is active\n    mapping(address wallet => mapping(uint96 nonce => mapping(bytes32 key => bytes32 value))) public walletStorage;\n\n    /// @notice Currently active nonce-script pair for a wallet, if any, for which storage is accessible\n    mapping(address wallet => NonceScript) internal activeNonceScript;\n\n    /**\n     * @notice Return whether a nonce has been exhausted; note that if a nonce is not set, that does not mean it has not been used before\n     * @param wallet Address of the wallet owning the nonce\n     * @param nonce Nonce to check\n     * @return Whether the nonce has been exhausted\n     */\n    function isNonceSet(address wallet, uint96 nonce) public view returns (bool) {\n        (uint256 bucket, uint256 mask) = getBucket(nonce);\n        return isNonceSetInternal(wallet, bucket, mask);\n    }\n\n    /// @dev Returns if a given nonce is set for a wallet, using the nonce's bucket and mask\n    function isNonceSetInternal(address wallet, uint256 bucket, uint256 mask) internal view returns (bool) {\n        return (nonces[wallet][bucket] & mask) != 0;\n    }\n\n    /**\n     * @notice Returns the next valid unset nonce for a given wallet\n     * @dev Any unset nonce is valid to use, but using this method\n     * increases the likelihood that the nonce you use will be in a bucket that\n     * has already been written to, which costs less gas\n     * @param wallet Address of the wallet to find the next nonce for\n     * @return The next unused nonce\n     */\n    function nextNonce(address wallet) external view returns (uint96) {\n        // Any bucket larger than `type(uint88).max` will result in unsafe undercast when converting to nonce\n        for (uint256 bucket = 0; bucket <= type(uint88).max; ++bucket) {\n            uint96 bucketValue = uint96(bucket << 8);\n            uint256 bucketNonces = nonces[wallet][bucket];\n            // Move on to the next bucket if all bits in this bucket are already set\n            if (bucketNonces == type(uint256).max) continue;\n            for (uint256 maskOffset = 0; maskOffset < 256; ++maskOffset) {\n                uint256 mask = 1 << maskOffset;\n                if ((bucketNonces & mask) == 0) {\n                    uint96 nonce = uint96(bucketValue + maskOffset);\n                    // The next available nonce should not be reserved for a replayable transaction\n                    if (nonceScriptAddress[wallet][nonce] == address(0)) {\n                        return nonce;\n                    }\n                }\n            }\n        }\n\n        revert NoUnusedNonces();\n    }\n\n    /**\n     * @notice Return the script address associated with the currently active nonce; revert if none\n     * @return Currently active script address\n     */\n    function getActiveScript() external view returns (address) {\n        address scriptAddress = activeNonceScript[msg.sender].scriptAddress;\n        if (scriptAddress == address(0)) {\n            revert NoActiveNonce();\n        }\n        return scriptAddress;\n    }\n\n    /// @dev Locate a nonce at a (bucket, mask) bitset position in the nonces mapping\n    function getBucket(uint96 nonce) internal pure returns (uint256, /* bucket */ uint256 /* mask */ ) {\n        uint256 bucket = nonce >> 8;\n        uint256 setMask = 1 << (nonce & 0xff);\n        return (bucket, setMask);\n    }\n\n    /// @notice Clears (un-sets) the active nonce to allow its reuse; allows a script to be replayed\n    function clearNonce() external {\n        if (activeNonceScript[msg.sender].scriptAddress == address(0)) {\n            revert NoActiveNonce();\n        }\n\n        uint96 nonce = activeNonceScript[msg.sender].nonce;\n        (uint256 bucket, uint256 setMask) = getBucket(nonce);\n        nonces[msg.sender][bucket] &= ~setMask;\n        emit ClearNonce(msg.sender, nonce);\n    }\n\n    /**\n     * @notice Set a given nonce for the calling wallet; effectively cancels any replayable script using that nonce\n     * @param nonce Nonce to set for the calling wallet\n     */\n    function setNonce(uint96 nonce) external {\n        // TODO: should we check whether there exists a nonceScriptAddress?\n        (uint256 bucket, uint256 setMask) = getBucket(nonce);\n        setNonceInternal(bucket, setMask);\n    }\n\n    /// @dev Set a nonce for the msg.sender, using the nonce's bucket and mask\n    function setNonceInternal(uint256 bucket, uint256 setMask) internal {\n        nonces[msg.sender][bucket] |= setMask;\n    }\n\n    /**\n     * @notice Set a wallet nonce as the active nonce and yield control back to the wallet by calling into callback\n     * @param nonce Nonce to activate for the transaction\n     * @param scriptAddress Address of script to invoke with nonce lock\n     * @param scriptCalldata Calldata for script call to invoke with nonce lock\n     * @return Return value from the executed operation\n     * @dev The script is expected to clearNonce() if it wishes to be replayable\n     */\n    function setActiveNonceAndCallback(uint96 nonce, address scriptAddress, bytes calldata scriptCalldata)\n        external\n        returns (bytes memory)\n    {\n        // retrieve the (bucket, mask) pair that addresses the nonce in memory\n        (uint256 bucket, uint256 setMask) = getBucket(nonce);\n\n        // ensure nonce is not already set\n        if (isNonceSetInternal(msg.sender, bucket, setMask)) {\n            revert NonceAlreadySet();\n        }\n\n        address cachedScriptAddress = nonceScriptAddress[msg.sender][nonce];\n        // if the nonce has been used before, check if the script address matches, and revert if not\n        if ((cachedScriptAddress != address(0)) && (cachedScriptAddress != scriptAddress)) {\n            revert NonceScriptMismatch();\n        }\n\n        // spend the nonce; only if the callee chooses to clear it will it get un-set and become replayable\n        setNonceInternal(bucket, setMask);\n\n        // set the nonce-script pair active and yield to the wallet callback\n        NonceScript memory previousNonceScript = activeNonceScript[msg.sender];\n        activeNonceScript[msg.sender] = NonceScript({nonce: nonce, scriptAddress: scriptAddress});\n\n        bytes memory result = IQuarkWallet(msg.sender).executeScriptWithNonceLock(scriptAddress, scriptCalldata);\n\n        // if a nonce was cleared, set the nonceScriptAddress to lock nonce re-use to the same script address\n        if (cachedScriptAddress == address(0) && !isNonceSetInternal(msg.sender, bucket, setMask)) {\n            nonceScriptAddress[msg.sender][nonce] = scriptAddress;\n        }\n\n        // release the nonce when the wallet finishes executing callback\n        activeNonceScript[msg.sender] = previousNonceScript;\n\n        return result;\n    }\n\n    /// @notice Write arbitrary bytes to storage namespaced by the currently active nonce; reverts if no nonce is currently active\n    function write(bytes32 key, bytes32 value) external {\n        if (activeNonceScript[msg.sender].scriptAddress == address(0)) {\n            revert NoActiveNonce();\n        }\n        walletStorage[msg.sender][activeNonceScript[msg.sender].nonce][key] = value;\n    }\n\n    /**\n     * @notice Read from storage namespaced by the currently active nonce; reverts if no nonce is currently active\n     * @return Value at the nonce storage location, as bytes\n     */\n    function read(bytes32 key) external view returns (bytes32) {\n        if (activeNonceScript[msg.sender].scriptAddress == address(0)) {\n            revert NoActiveNonce();\n        }\n        return walletStorage[msg.sender][activeNonceScript[msg.sender].nonce][key];\n    }\n}\n"
      },
      "src/quark-core/src/interfaces/IQuarkWallet.sol": {
        "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.23;\n\n/**\n * @title Quark Wallet interface\n * @notice An interface for interacting with Quark Wallets\n * @author Compound Labs, Inc.\n */\ninterface IQuarkWallet {\n    /// @notice The structure of a signed operation to execute in the context of this wallet\n    struct QuarkOperation {\n        /// @notice Nonce identifier for the operation\n        uint96 nonce;\n        /// @notice The address of the transaction script to run\n        address scriptAddress;\n        /// @notice Creation codes Quark must ensure are deployed before executing this operation\n        bytes[] scriptSources;\n        /// @notice Encoded function selector + arguments to invoke on the script contract\n        bytes scriptCalldata;\n        /// @notice Expiration time for the signature corresponding to this operation\n        uint256 expiry;\n    }\n\n    function executeQuarkOperation(QuarkOperation calldata op, uint8 v, bytes32 r, bytes32 s)\n        external\n        returns (bytes memory);\n    function executeMultiQuarkOperation(\n        QuarkOperation calldata op,\n        bytes32[] memory opDigests,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (bytes memory);\n    function executeScript(\n        uint96 nonce,\n        address scriptAddress,\n        bytes calldata scriptCalldata,\n        bytes[] calldata scriptSources\n    ) external returns (bytes memory);\n    function getDigestForQuarkOperation(QuarkOperation calldata op) external view returns (bytes32);\n    function getDigestForMultiQuarkOperation(bytes32[] memory opDigests) external pure returns (bytes32);\n    function getDigestForQuarkMessage(bytes memory message) external view returns (bytes32);\n    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4);\n    function executeScriptWithNonceLock(address scriptAddress, bytes memory scriptCalldata)\n        external\n        returns (bytes memory);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "test/=test/",
        "codejar/=src/codejar/",
        "legend-scripts/=src/legend-scripts/",
        "quark-core/=src/quark-core/",
        "quark-core-scripts/=src/quark-core-scripts/",
        "quark-factory/=src/quark-factory/",
        "quark-proxy/=src/quark-proxy/",
        "@uniswap/=lib/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "v3-core/=lib/v3-core/",
        "v3-periphery/=lib/v3-periphery/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": true,
      "libraries": {}
    }
  }}