{
  "address": "0xaee0e2c4d5ab2fc164c8b0cc8d3118c1c752c95e",
  "abi": [
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "offset",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "length",
          "type": "uint256"
        }
      ],
      "name": "OffsetOutOfBoundsError",
      "type": "error"
    },
    {
      "inputs": [
        {
          "internalType": "bytes",
          "name": "key",
          "type": "bytes"
        },
        {
          "internalType": "bytes",
          "name": "data",
          "type": "bytes"
        },
        {
          "internalType": "bytes",
          "name": "sig",
          "type": "bytes"
        }
      ],
      "name": "verify",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    }
  ],
  "contractName": "RSASHA256Algorithm",
  "sourceName": "contracts/dnssec-oracle/algorithms/RSASHA256Algorithm.sol",
  "bytecode": "0x6080604052348015600f57600080fd5b50610afb8061001f6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063de8f50a114610030575b600080fd5b61004361003e3660046108bd565b610057565b604051901515815260200160405180910390f35b600060608060006100a260048b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506102c89050565b60ff169050801561016e576100f760058261ffff168c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b9250610167610107826005610992565b61ffff9081169060059061011d9085168d6109ac565b61012791906109ac565b8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b9150610227565b6101b260058b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505061035e9050565b90506101fe60078261ffff168c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b925061022461020e826007610992565b61ffff9081169060079061011d9085168d6109ac565b91505b6102ba828488888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516002925061027591508e908e906109bf565b602060405180830381855afa158015610292573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906102b591906109cf565b61037b565b9a9950505050505050505050565b60006102de836102d98460016109e8565b6103f3565b8282815181106102f0576102f06109fb565b016020015160f81c90505b92915050565b60608167ffffffffffffffff81111561031c5761031c610a2a565b6040519080825280601f01601f191660200182016040528015610346576020820181803683370190505b509050610357848483600086610448565b9392505050565b600061036f836102d98460026109e8565b50016020015160f01c90565b60008060006103c18787876040518060400160405280601381526020017f3031300d06096086480165030402010500042000000000000000000000000000815250610480565b915091508180156103e857506103e5602082516103de91906109ac565b82906106e5565b84145b979650505050505050565b81518111156104445781516040517f8a3c1cfb00000000000000000000000000000000000000000000000000000000815261043b918391600401918252602082015260400190565b60405180910390fd5b5050565b610456856102d983876109e8565b610464836102d983856109e8565b610479826020850101856020880101836106ff565b5050505050565b60006060600080610492888888610785565b915091508115806104a557508751815114155b156104b7576000935091506106dc9050565b806000815181106104ca576104ca6109fb565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615158061055857508060018151811061050c5761050c6109fb565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f010000000000000000000000000000000000000000000000000000000000000014155b1561056a576000935091506106dc9050565b60008551600f1461057c57602061057f565b60145b60ff169050600081835161059391906109ac565b905060008751826105a491906109ac565b9050836105b26001836109ac565b815181106105c2576105c26109fb565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016156105ff576000849650965050505050506106dc565b875161061390859083908b906000906107a0565b610628576000849650965050505050506106dc565b600060026106376001846109ac565b61064191906109ac565b9050600881101561065e57600085975097505050505050506106dc565b60025b61066c6001846109ac565b8110156106ce57858181518110610685576106856109fb565b01602001517fff00000000000000000000000000000000000000000000000000000000000000908116146106c65760008698509850505050505050506106dc565b600101610661565b506001975093955050505050505b94509492505050565b60006106f6836102d98460206109e8565b50016020015190565b5b601f81111561073e5781518352602092830192909101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001610700565b801561078057815183516001602084900360031b1b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161783525b505050565b600060606107948385876107c3565b91509150935093915050565b60006107ad84848461085a565b6107b887878561085a565b149695505050505050565b6000606060008551855185518888886040516020016107e796959493929190610a89565b6040516020818303038152906040529050835167ffffffffffffffff81111561081257610812610a2a565b6040519080825280601f01601f19166020018201604052801561083c576020820181803683370190505b50915083516020830182516020840160055afa925050935093915050565b600061086a846102d984866109e8565b5091016020012090565b60008083601f84011261088657600080fd5b50813567ffffffffffffffff81111561089e57600080fd5b6020830191508360208285010111156108b657600080fd5b9250929050565b600080600080600080606087890312156108d657600080fd5b863567ffffffffffffffff8111156108ed57600080fd5b6108f989828a01610874565b909750955050602087013567ffffffffffffffff81111561091957600080fd5b61092589828a01610874565b909550935050604087013567ffffffffffffffff81111561094557600080fd5b61095189828a01610874565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff81811683821601908111156102fb576102fb610963565b818103818111156102fb576102fb610963565b8183823760009101908152919050565b6000602082840312156109e157600080fd5b5051919050565b808201808211156102fb576102fb610963565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000815160005b81811015610a7a5760208185018101518683015201610a60565b50600093019283525090919050565b8681528560208201528460408201526000610ab9610ab3610aad6060850188610a59565b86610a59565b84610a59565b9897505050505050505056fea2646970667358221220335ba623c7b8866af790ac308322c39a6ebbb7d4fae75897391e659f245c261264736f6c634300081a0033",
  "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063de8f50a114610030575b600080fd5b61004361003e3660046108bd565b610057565b604051901515815260200160405180910390f35b600060608060006100a260048b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506102c89050565b60ff169050801561016e576100f760058261ffff168c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b9250610167610107826005610992565b61ffff9081169060059061011d9085168d6109ac565b61012791906109ac565b8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b9150610227565b6101b260058b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505061035e9050565b90506101fe60078261ffff168c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506103019050565b925061022461020e826007610992565b61ffff9081169060079061011d9085168d6109ac565b91505b6102ba828488888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040516002925061027591508e908e906109bf565b602060405180830381855afa158015610292573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906102b591906109cf565b61037b565b9a9950505050505050505050565b60006102de836102d98460016109e8565b6103f3565b8282815181106102f0576102f06109fb565b016020015160f81c90505b92915050565b60608167ffffffffffffffff81111561031c5761031c610a2a565b6040519080825280601f01601f191660200182016040528015610346576020820181803683370190505b509050610357848483600086610448565b9392505050565b600061036f836102d98460026109e8565b50016020015160f01c90565b60008060006103c18787876040518060400160405280601381526020017f3031300d06096086480165030402010500042000000000000000000000000000815250610480565b915091508180156103e857506103e5602082516103de91906109ac565b82906106e5565b84145b979650505050505050565b81518111156104445781516040517f8a3c1cfb00000000000000000000000000000000000000000000000000000000815261043b918391600401918252602082015260400190565b60405180910390fd5b5050565b610456856102d983876109e8565b610464836102d983856109e8565b610479826020850101856020880101836106ff565b5050505050565b60006060600080610492888888610785565b915091508115806104a557508751815114155b156104b7576000935091506106dc9050565b806000815181106104ca576104ca6109fb565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615158061055857508060018151811061050c5761050c6109fb565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f010000000000000000000000000000000000000000000000000000000000000014155b1561056a576000935091506106dc9050565b60008551600f1461057c57602061057f565b60145b60ff169050600081835161059391906109ac565b905060008751826105a491906109ac565b9050836105b26001836109ac565b815181106105c2576105c26109fb565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016156105ff576000849650965050505050506106dc565b875161061390859083908b906000906107a0565b610628576000849650965050505050506106dc565b600060026106376001846109ac565b61064191906109ac565b9050600881101561065e57600085975097505050505050506106dc565b60025b61066c6001846109ac565b8110156106ce57858181518110610685576106856109fb565b01602001517fff00000000000000000000000000000000000000000000000000000000000000908116146106c65760008698509850505050505050506106dc565b600101610661565b506001975093955050505050505b94509492505050565b60006106f6836102d98460206109e8565b50016020015190565b5b601f81111561073e5781518352602092830192909101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001610700565b801561078057815183516001602084900360031b1b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161783525b505050565b600060606107948385876107c3565b91509150935093915050565b60006107ad84848461085a565b6107b887878561085a565b149695505050505050565b6000606060008551855185518888886040516020016107e796959493929190610a89565b6040516020818303038152906040529050835167ffffffffffffffff81111561081257610812610a2a565b6040519080825280601f01601f19166020018201604052801561083c576020820181803683370190505b50915083516020830182516020840160055afa925050935093915050565b600061086a846102d984866109e8565b5091016020012090565b60008083601f84011261088657600080fd5b50813567ffffffffffffffff81111561089e57600080fd5b6020830191508360208285010111156108b657600080fd5b9250929050565b600080600080600080606087890312156108d657600080fd5b863567ffffffffffffffff8111156108ed57600080fd5b6108f989828a01610874565b909750955050602087013567ffffffffffffffff81111561091957600080fd5b61092589828a01610874565b909550935050604087013567ffffffffffffffff81111561094557600080fd5b61095189828a01610874565b979a9699509497509295939492505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff81811683821601908111156102fb576102fb610963565b818103818111156102fb576102fb610963565b8183823760009101908152919050565b6000602082840312156109e157600080fd5b5051919050565b808201808211156102fb576102fb610963565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000815160005b81811015610a7a5760208185018101518683015201610a60565b50600093019283525090919050565b8681528560208201528460408201526000610ab9610ab3610aad6060850188610a59565b86610a59565b84610a59565b9897505050505050505056fea2646970667358221220335ba623c7b8866af790ac308322c39a6ebbb7d4fae75897391e659f245c261264736f6c634300081a0033",
  "linkReferences": {},
  "deployedLinkReferences": {},
  "immutableReferences": {},
  "inputSourceName": "project/contracts/dnssec-oracle/algorithms/RSASHA256Algorithm.sol",
  "devdoc": {
    "details": "Implements the DNSSEC RSASHA256 algorithm.",
    "errors": {
      "OffsetOutOfBoundsError(uint256,uint256)": [
        {
          "details": "`offset` was beyond `length`.       Error selector: `0x8a3c1cfb`"
        }
      ]
    },
    "kind": "dev",
    "methods": {},
    "version": 1
  },
  "evm": {
    "gasEstimates": {
      "creation": {
        "codeDepositCost": "562200",
        "executionCost": "594",
        "totalCost": "562794"
      },
      "external": {
        "verify(bytes,bytes,bytes)": "infinite"
      }
    }
  },
  "metadata": "{\"compiler\":{\"version\":\"0.8.26+commit.8a97fa7a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"OffsetOutOfBoundsError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"key\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implements the DNSSEC RSASHA256 algorithm.\",\"errors\":{\"OffsetOutOfBoundsError(uint256,uint256)\":[{\"details\":\"`offset` was beyond `length`.       Error selector: `0x8a3c1cfb`\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"project/contracts/dnssec-oracle/algorithms/RSASHA256Algorithm.sol\":\"RSASHA256Algorithm\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\"project/:@ensdomains/solsha1/=npm/@ensdomains/solsha1@0.0.3/\"]},\"sources\":{\"project/contracts/dnssec-oracle/algorithms/Algorithm.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\n/// @dev An interface for contracts implementing a DNSSEC (signing) algorithm.\\ninterface Algorithm {\\n    /// @dev Verifies a signature.\\n    /// @param key The public key to verify with.\\n    /// @param data The signed data to verify.\\n    /// @param signature The signature to verify.\\n    /// @return True iff the signature is valid.\\n    function verify(\\n        bytes calldata key,\\n        bytes calldata data,\\n        bytes calldata signature\\n    ) external view virtual returns (bool);\\n}\\n\",\"keccak256\":\"0xbcbdc06d72b64903e733e7ddfbf59c35c984c3eb0022baacab12c97292cc13df\"},\"project/contracts/dnssec-oracle/algorithms/ModexpPrecompile.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nlibrary ModexpPrecompile {\\n    /// @dev Computes (base ^ exponent) % modulus over big numbers.\\n    function modexp(\\n        bytes memory base,\\n        bytes memory exponent,\\n        bytes memory modulus\\n    ) internal view returns (bool success, bytes memory output) {\\n        bytes memory input = abi.encodePacked(\\n            uint256(base.length),\\n            uint256(exponent.length),\\n            uint256(modulus.length),\\n            base,\\n            exponent,\\n            modulus\\n        );\\n\\n        output = new bytes(modulus.length);\\n\\n        assembly {\\n            success := staticcall(\\n                gas(),\\n                5,\\n                add(input, 32),\\n                mload(input),\\n                add(output, 32),\\n                mload(modulus)\\n            )\\n        }\\n    }\\n}\\n\",\"keccak256\":\"0x06457e4fc1eda1e2ba6ef08cb270983756e760bdeaa3155e1ca69a5f4bc5dd1f\"},\"project/contracts/dnssec-oracle/algorithms/RSAPKCS1Verify.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nimport \\\"./RSAVerify.sol\\\";\\nimport \\\"../../utils/BytesUtils.sol\\\";\\n\\n/// @dev Library for PKCS#1 v1.5 signature verification\\nlibrary RSAPKCS1Verify {\\n    using BytesUtils for *;\\n\\n    /// @dev PKCS#1 v1.5 DigestInfo prefix for SHA-1\\n    bytes constant SHA1_DIGEST_INFO = hex\\\"3021300906052b0e03021a05000414\\\";\\n\\n    /// @dev PKCS#1 v1.5 DigestInfo prefix for SHA-256\\n    bytes constant SHA256_DIGEST_INFO = hex\\\"3031300d060960864801650304020105000420\\\";\\n\\n    /// @dev Verifies an RSA signature with PKCS#1 v1.5 padding for SHA-1\\n    function verifySHA1(\\n        bytes memory modulus,\\n        bytes memory exponent,\\n        bytes memory sig,\\n        bytes20 hash\\n    ) internal view returns (bool) {\\n        (bool ok, bytes memory result) = recoverAndVerify(modulus, exponent, sig, SHA1_DIGEST_INFO);\\n        return ok && hash == result.readBytes20(result.length - 20);\\n    }\\n\\n    /// @dev Verifies an RSA signature with PKCS#1 v1.5 padding for SHA-256\\n    function verifySHA256(\\n        bytes memory modulus,\\n        bytes memory exponent,\\n        bytes memory sig,\\n        bytes32 hash\\n    ) internal view returns (bool) {\\n        (bool ok, bytes memory result) = recoverAndVerify(modulus, exponent, sig, SHA256_DIGEST_INFO);\\n        return ok && hash == result.readBytes32(result.length - 32);\\n    }\\n\\n    /// @dev Recovers RSA signature and verifies PKCS#1 v1.5 structure\\n    /// Format: 0x00 0x01 [0xFF padding] 0x00 [DigestInfo] [Hash]\\n    /// https://datatracker.ietf.org/doc/html/rfc8017#section-9.2\\n    function recoverAndVerify(\\n        bytes memory modulus,\\n        bytes memory exponent,\\n        bytes memory sig,\\n        bytes memory digestInfo\\n    ) private view returns (bool, bytes memory) {\\n        (bool ok, bytes memory result) = RSAVerify.rsarecover(modulus, exponent, sig);\\n        if (!ok || result.length != modulus.length) {\\n            return (false, result);\\n        }\\n\\n        // Check leading bytes: 0x00 0x01\\n        if (result[0] != 0x00 || result[1] != 0x01) {\\n            return (false, result);\\n        }\\n\\n        // Calculate positions working backwards from the end\\n        uint256 hashLen = digestInfo.length == 15 ? 20 : 32;\\n        uint256 hashStart = result.length - hashLen;\\n        uint256 digestInfoStart = hashStart - digestInfo.length;\\n\\n        // Verify 0x00 separator before DigestInfo\\n        if (result[digestInfoStart - 1] != 0x00) {\\n            return (false, result);\\n        }\\n\\n        // Verify DigestInfo matches expected value\\n        if (!result.equals(digestInfoStart, digestInfo, 0, digestInfo.length)) {\\n            return (false, result);\\n        }\\n\\n        // Verify padding: all bytes from position 2 to separator must be 0xFF\\n        // Minimum 8 bytes of 0xFF padding required (RFC 3447)\\n        uint256 paddingLen = digestInfoStart - 1 - 2;\\n        if (paddingLen < 8) {\\n            return (false, result);\\n        }\\n        for (uint256 i = 2; i < digestInfoStart - 1; i++) {\\n            if (result[i] != 0xFF) {\\n                return (false, result);\\n            }\\n        }\\n\\n        return (true, result);\\n    }\\n}\\n\",\"keccak256\":\"0x92c872f6bb94670de46829d61122fcb0b0642dbd8e0e6fe31d2e8d387c890e87\"},\"project/contracts/dnssec-oracle/algorithms/RSASHA256Algorithm.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nimport \\\"./Algorithm.sol\\\";\\nimport \\\"./RSAPKCS1Verify.sol\\\";\\nimport \\\"../../utils/BytesUtils.sol\\\";\\n\\n/// @dev Implements the DNSSEC RSASHA256 algorithm.\\ncontract RSASHA256Algorithm is Algorithm {\\n    using BytesUtils for *;\\n\\n    function verify(\\n        bytes calldata key,\\n        bytes calldata data,\\n        bytes calldata sig\\n    ) external view override returns (bool) {\\n        bytes memory exponent;\\n        bytes memory modulus;\\n\\n        uint16 exponentLen = uint16(key.readUint8(4));\\n        if (exponentLen != 0) {\\n            exponent = key.substring(5, exponentLen);\\n            modulus = key.substring(\\n                exponentLen + 5,\\n                key.length - exponentLen - 5\\n            );\\n        } else {\\n            exponentLen = key.readUint16(5);\\n            exponent = key.substring(7, exponentLen);\\n            modulus = key.substring(\\n                exponentLen + 7,\\n                key.length - exponentLen - 7\\n            );\\n        }\\n\\n        return RSAPKCS1Verify.verifySHA256(modulus, exponent, sig, sha256(data));\\n    }\\n}\\n\",\"keccak256\":\"0x7fcee47279521f12f45867173e778ccf575f3af26d880132927897bb1b12889e\"},\"project/contracts/dnssec-oracle/algorithms/RSAVerify.sol\":{\"content\":\"pragma solidity ^0.8.4;\\n\\nimport \\\"./ModexpPrecompile.sol\\\";\\nimport \\\"../../utils/BytesUtils.sol\\\";\\n\\nlibrary RSAVerify {\\n    /// @dev Recovers the input data from an RSA signature, returning the result in S.\\n    /// @param N The RSA public modulus.\\n    /// @param E The RSA public exponent.\\n    /// @param S The signature to recover.\\n    /// @return True if the recovery succeeded.\\n    function rsarecover(\\n        bytes memory N,\\n        bytes memory E,\\n        bytes memory S\\n    ) internal view returns (bool, bytes memory) {\\n        return ModexpPrecompile.modexp(S, E, N);\\n    }\\n}\\n\",\"keccak256\":\"0x3de747c1a48c82031e79a35c6b844697e48c8d0549cb3475783b1447895ef8ab\"},\"project/contracts/utils/BytesUtils.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {LibMem} from \\\"./LibMem/LibMem.sol\\\";\\n\\nlibrary BytesUtils {\\n    /// @dev `offset` was beyond `length`.\\n    ///       Error selector: `0x8a3c1cfb`\\n    error OffsetOutOfBoundsError(uint256 offset, uint256 length);\\n\\n    /// @dev Assert `end` is not beyond the length of `v`.\\n    function _checkBound(bytes memory v, uint256 end) internal pure {\\n        if (end > v.length) {\\n            revert OffsetOutOfBoundsError(end, v.length);\\n        }\\n    }\\n\\n    /// @dev Compute `keccak256(v[off:off+len])`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @param len The number of bytes to hash.\\n    /// @return ret The corresponding hash.\\n    function keccak(\\n        bytes memory v,\\n        uint256 off,\\n        uint256 len\\n    ) internal pure returns (bytes32 ret) {\\n        _checkBound(v, off + len);\\n        assembly (\\\"memory-safe\\\") {\\n            ret := keccak256(add(add(v, 32), off), len)\\n        }\\n    }\\n\\n    /// @dev Lexicographically compare two byte strings.\\n    /// @param vA The first bytes to compare.\\n    /// @param vB The second bytes to compare.\\n    /// @return Positive number if `A > B`, negative number if `A < B`, or zero if `A == B`.\\n    function compare(\\n        bytes memory vA,\\n        bytes memory vB\\n    ) internal pure returns (int256) {\\n        return compare(vA, 0, vA.length, vB, 0, vB.length);\\n    }\\n\\n    /// @dev Lexicographically compare two byte ranges: `A = vA[offA:offA+lenA]` and `B = vB[offB:offB+lenB]`.\\n    /// @param vA The first bytes.\\n    /// @param offA The offset of the first bytes.\\n    /// @param lenA The length of the first bytes.\\n    /// @param vB The second bytes.\\n    /// @param offB The offset of the second bytes.\\n    /// @param lenB The length of the second bytes.\\n    /// @return Positive number if `A > B`, negative number if `A < B`, or zero if `A == B`.\\n    function compare(\\n        bytes memory vA,\\n        uint256 offA,\\n        uint256 lenA,\\n        bytes memory vB,\\n        uint256 offB,\\n        uint256 lenB\\n    ) internal pure returns (int256) {\\n        _checkBound(vA, offA + lenA);\\n        _checkBound(vB, offB + lenB);\\n        unchecked {\\n            uint256 ptrA = LibMem.ptr(vA) + offA;\\n            uint256 ptrB = LibMem.ptr(vB) + offB;\\n            uint256 shortest = lenA < lenB ? lenA : lenB;\\n            for (uint256 i; i < shortest; i += 32) {\\n                uint256 a = LibMem.load(ptrA + i);\\n                uint256 b = LibMem.load(ptrB + i);\\n                if (a != b) {\\n                    uint256 rest = shortest - i;\\n                    if (rest < 32) {\\n                        rest = (32 - rest) << 3; // bits to drop\\n                        a >>= rest; // shift out the\\n                        b >>= rest; // irrelevant bits\\n                    }\\n                    if (a < b) {\\n                        return -1;\\n                    } else if (a > b) {\\n                        return 1;\\n                    }\\n                }\\n            }\\n        }\\n        return int256(lenA) - int256(lenB);\\n    }\\n\\n    /// @dev Determine if `a[offA:offA+len] == b[offB:offB+len]`.\\n    /// @param vA The first bytes.\\n    /// @param offA The offset into the first bytes.\\n    /// @param vB The second bytes.\\n    /// @param offB The offset into the second bytes.\\n    /// @param len The number of bytes to compare.\\n    /// @return True if the byte ranges are equal.\\n    function equals(\\n        bytes memory vA,\\n        uint256 offA,\\n        bytes memory vB,\\n        uint256 offB,\\n        uint256 len\\n    ) internal pure returns (bool) {\\n        return keccak(vA, offA, len) == keccak(vB, offB, len);\\n    }\\n\\n    /// @dev Determine if `a[offA:] == b[offB:]`.\\n    /// @param vA The first bytes.\\n    /// @param offA The offset into the first bytes.\\n    /// @param vB The second bytes.\\n    /// @param offB The offset into the second bytes.\\n    /// @return True if the byte ranges are equal.\\n    function equals(\\n        bytes memory vA,\\n        uint256 offA,\\n        bytes memory vB,\\n        uint256 offB\\n    ) internal pure returns (bool) {\\n        _checkBound(vA, offA);\\n        _checkBound(vB, offB);\\n        unchecked {\\n            return\\n                keccak(vA, offA, vA.length - offA) ==\\n                keccak(vB, offB, vB.length - offB);\\n        }\\n    }\\n\\n    /// @dev Determine if `a[offA:] == b`.\\n    /// @param vA The first bytes.\\n    /// @param offA The offset into the first bytes.\\n    /// @param vB The second bytes.\\n    /// @return True if the byte ranges are equal.\\n    function equals(\\n        bytes memory vA,\\n        uint256 offA,\\n        bytes memory vB\\n    ) internal pure returns (bool) {\\n        return\\n            vA.length == offA + vB.length &&\\n            keccak(vA, offA, vB.length) == keccak256(vB);\\n    }\\n\\n    /// @dev Determine if `a == b`.\\n    /// @param vA The first bytes.\\n    /// @param vB The second bytes.\\n    /// @return True if the bytes are equal.\\n    function equals(\\n        bytes memory vA,\\n        bytes memory vB\\n    ) internal pure returns (bool) {\\n        return vA.length == vB.length && keccak256(vA) == keccak256(vB);\\n    }\\n\\n    /// @dev Returns `uint8(v[off])`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @return The corresponding `uint8`.\\n    function readUint8(\\n        bytes memory v,\\n        uint256 off\\n    ) internal pure returns (uint8) {\\n        _checkBound(v, off + 1);\\n        unchecked {\\n            return uint8(v[off]);\\n        }\\n    }\\n\\n    /// @dev Returns `uint16(bytes2(v[off:off+2]))`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @return ret The corresponding `uint16`.\\n    function readUint16(\\n        bytes memory v,\\n        uint256 off\\n    ) internal pure returns (uint16 ret) {\\n        _checkBound(v, off + 2);\\n        assembly (\\\"memory-safe\\\") {\\n            ret := shr(240, mload(add(add(v, 32), off)))\\n        }\\n    }\\n\\n    /// @dev Returns `uint32(bytes4(v[off:off+4]))`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @return ret The corresponding `uint32`.\\n    function readUint32(\\n        bytes memory v,\\n        uint256 off\\n    ) internal pure returns (uint32 ret) {\\n        _checkBound(v, off + 4);\\n        assembly (\\\"memory-safe\\\") {\\n            ret := shr(224, mload(add(add(v, 32), off)))\\n        }\\n    }\\n\\n    /// @dev Returns `bytes20(v[off:off+20])`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @return ret The corresponding `bytes20`.\\n    function readBytes20(\\n        bytes memory v,\\n        uint256 off\\n    ) internal pure returns (bytes20 ret) {\\n        _checkBound(v, off + 20);\\n        assembly (\\\"memory-safe\\\") {\\n            ret := shl(96, mload(add(add(v, 20), off)))\\n        }\\n    }\\n\\n    /// @dev Returns `bytes32(v[off:off+32])`.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @return ret The corresponding `bytes32`.\\n    function readBytes32(\\n        bytes memory v,\\n        uint256 off\\n    ) internal pure returns (bytes32 ret) {\\n        _checkBound(v, off + 32);\\n        assembly (\\\"memory-safe\\\") {\\n            ret := mload(add(add(v, 32), off))\\n        }\\n    }\\n\\n    /// @dev Returns `bytes32(bytesN(v[off:off+len]))`.\\n    ///      Accepts 0-32 bytes or reverts.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @param len The number of bytes.\\n    /// @return ret The corresponding N-bytes left-aligned in a `bytes32`.\\n    function readBytesN(\\n        bytes memory v,\\n        uint256 off,\\n        uint256 len\\n    ) internal pure returns (bytes32 ret) {\\n        assert(len <= 32);\\n        _checkBound(v, off + len);\\n        assembly (\\\"memory-safe\\\") {\\n            let mask := sub(shl(shl(3, sub(32, len)), 1), 1) // <(32-N)x00><NxFF>\\n            ret := and(mload(add(add(v, 32), off)), not(mask))\\n        }\\n    }\\n\\n    /// @dev Copy `vSrc[offSrc:offSrc+len]` to `vDst[offDst:offDst:len]`.\\n    /// @param vSrc The source bytes.\\n    /// @param offSrc The offset into the source to begin the copy.\\n    /// @param vDst The destination bytes.\\n    /// @param offDst The offset into the destination to place the copy.\\n    /// @param len The number of bytes to copy.\\n    function copyBytes(\\n        bytes memory vSrc,\\n        uint256 offSrc,\\n        bytes memory vDst,\\n        uint256 offDst,\\n        uint256 len\\n    ) internal pure {\\n        _checkBound(vSrc, offSrc + len);\\n        _checkBound(vDst, offDst + len);\\n        unchecked {\\n            LibMem.copy(\\n                LibMem.ptr(vDst) + offDst,\\n                LibMem.ptr(vSrc) + offSrc,\\n                len\\n            );\\n        }\\n    }\\n\\n    /// @dev Copies a substring into a new byte string.\\n    /// @param vSrc The byte string to copy from.\\n    /// @param off The offset to start copying at.\\n    /// @param len The number of bytes to copy.\\n    /// @return vDst The copied substring.\\n    function substring(\\n        bytes memory vSrc,\\n        uint256 off,\\n        uint256 len\\n    ) internal pure returns (bytes memory vDst) {\\n        vDst = new bytes(len);\\n        copyBytes(vSrc, off, vDst, 0, len);\\n    }\\n\\n    /// @dev Find the first occurrence of `needle`.\\n    /// @param v The bytes to search.\\n    /// @param off The offset to start searching.\\n    /// @param len The number of bytes to search.\\n    /// @param needle The byte to search for.\\n    /// @return The offset of `needle`, or `type(uint256).max` if not found.\\n    function find(\\n        bytes memory v,\\n        uint256 off,\\n        uint256 len,\\n        bytes1 needle\\n    ) internal pure returns (uint256) {\\n        for (uint256 end = off + len; off < end; off++) {\\n            if (v[off] == needle) {\\n                return off;\\n            }\\n        }\\n        return type(uint256).max;\\n    }\\n\\n    /// @dev Returns `true` if word contains a zero byte.\\n    function hasZeroByte(uint256 word) internal pure returns (bool) {\\n        unchecked {\\n            return\\n                ((~word &\\n                    (word -\\n                        0x0101010101010101010101010101010101010101010101010101010101010101)) &\\n                    0x8080808080808080808080808080808080808080808080808080808080808080) !=\\n                0;\\n        }\\n    }\\n\\n    /// @dev Efficiently check if `v[off:off+len]` contains `needle` byte.\\n    /// @param v The source bytes.\\n    /// @param off The offset into the source.\\n    /// @param len The number of bytes to search.\\n    /// @param needle The byte to search for.\\n    /// @return found `true` if `needle` was found.\\n    function includes(\\n        bytes memory v,\\n        uint256 off,\\n        uint256 len,\\n        bytes1 needle\\n    ) internal pure returns (bool found) {\\n        _checkBound(v, off + len);\\n        unchecked {\\n            uint256 wide = uint8(needle);\\n            wide |= wide << 8;\\n            wide |= wide << 16;\\n            wide |= wide << 32;\\n            wide |= wide << 64;\\n            wide |= wide << 128; // broadcast byte across word\\n            off += LibMem.ptr(v);\\n            len += off;\\n            while (off < len) {\\n                uint256 word = LibMem.load(off) ^ wide; // zero needle byte\\n                off += 32;\\n                if (hasZeroByte(word)) {\\n                    return\\n                        off <= len ||\\n                        hasZeroByte(\\n                            word | ((1 << ((off - len) << 3)) - 1) // recheck overflow by making it nonzero\\n                        );\\n                }\\n            }\\n        }\\n    }\\n}\\n\",\"keccak256\":\"0xcda2585a719e1a8974b5b44357e5d21417e1308b1d1f4d26b244d4ff0bb5b02d\",\"license\":\"MIT\"},\"project/contracts/utils/LibMem/LibMem.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity ^0.8.13;\\n\\nlibrary LibMem {\\n    /// @dev Copy `mem[src:src+len]` to `mem[dst:dst+len]`.\\n    ///      Equivalent to `mcopy()`.\\n    ///\\n    /// @param src The source memory offset.\\n    /// @param dst The destination memory offset.\\n    /// @param len The number of bytes to copy.\\n    function copy(uint256 dst, uint256 src, uint256 len) internal pure {\\n        assembly {\\n            // Copy word-length chunks while possible\\n            // prettier-ignore\\n            for {} gt(len, 31) {} {\\n                mstore(dst, mload(src))\\n                dst := add(dst, 32)\\n                src := add(src, 32)\\n                len := sub(len, 32)\\n            }\\n            // Copy remaining bytes\\n            if len {\\n                let mask := sub(shl(shl(3, sub(32, len)), 1), 1)\\n                let wSrc := and(mload(src), not(mask))\\n                let wDst := and(mload(dst), mask)\\n                mstore(dst, or(wSrc, wDst))\\n            }\\n        }\\n    }\\n\\n    /// @dev Convert bytes to a memory offset.\\n    ///\\n    /// @param v The bytes to convert.\\n    ///\\n    /// @return ret The corresponding memory offset.\\n    function ptr(bytes memory v) internal pure returns (uint256 ret) {\\n        assembly {\\n            ret := add(v, 32)\\n        }\\n    }\\n\\n    /// @dev Read word at memory offset.\\n    ///\\n    /// @param src The memory offset.\\n    ///\\n    /// @return ret The read word.\\n    function load(uint256 src) internal pure returns (uint256 ret) {\\n        assembly {\\n            ret := mload(src)\\n        }\\n    }\\n}\\n\",\"keccak256\":\"0x066f29ad3a39392786ff3caf9ba120104ffaa55502f71158631411db46d1ec89\",\"license\":\"MIT\"}},\"version\":1}",
  "storageLayout": {
    "storage": [],
    "types": null
  },
  "userdoc": {
    "kind": "user",
    "methods": {},
    "version": 1
  },
  "argsData": "0x",
  "transaction": {
    "hash": "0x5d663405adc50bd10a4af5becba7566c44ade9223a01cb7daf92af45656ce678",
    "nonce": "0x1",
    "origin": "0x4e472d50f3d735e76a143afcadae7f03db6995de"
  },
  "receipt": {
    "blockHash": "0xe81b997aaf1faff770811945554e2ee45615db96fca0c1cf3f933e3492181015",
    "blockNumber": "0x1763f18",
    "transactionIndex": "0x2b"
  }
}